Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript : Insane boolean test with '!' operator [duplicate]

On inputting the following function call into chrome console:

(function(regex, str){
    console.log(regex.test(str))
    console.log(!regex.test(str))
    console.log(! regex.test(str))
    console.log( !regex.test(str))
    console.log( ! regex.test(str))
})(new RegExp("new", "gmi"), "new")

I get the following results:

true
true
false
true
false

Can someone explain why the 3rd and 5th tests return false? And why the First and Second both return true.

like image 346
Joe Butler Avatar asked Jan 29 '15 14:01

Joe Butler


2 Answers

You're including the "g" modifier, so the regular expression object is maintaining the state of the match progress. Each call is not the same, in other words.

Your first call matches the string "new", and the regex updates the position to the end of the string. The next match fails (so you see true for !regexp.test(str)). It fails because the string "new" does not appear at the end of the string "new".

Now we've run off the end of the string, so the next test starts over like the first. It matches again, so your ! turns that true to false. The one after that doesn't match, and the one after that will have started over again and it matches.

Note that the spaces around ! in the tests have absolutely nothing to do with the behavior.

edit — try this variation:

(function(regex, str){
    console.log(regex.test(str) + " - " + regex.lastIndex)
    console.log(!regex.test(str) + " - " + regex.lastIndex)
    console.log(! regex.test(str) + " - " + regex.lastIndex)
    console.log( !regex.test(str) + " - " + regex.lastIndex)
    console.log( ! regex.test(str) + " - " + regex.lastIndex)
})(new RegExp("new", "gmi"), "new")

You'll see that the .lastIndex property toggles between 0 and 3.

I think that the moral of this story is "don't use 'g' unless you really know you want to."

like image 165
Pointy Avatar answered Oct 03 '22 17:10

Pointy


I'll explain you what's happening. Go through the comments. Its in the form of

regex.lastIndex, actual value, negated value

// code below

(function(regex, str){
    console.log(regex.test(str)) // 0, true, false
    console.log(!regex.test(str)) // 3, false, true => lastIndex set to 0
    console.log(! regex.test(str)) // 0, true, false
    console.log( !regex.test(str)) // 3, false, true => lastIndex set to 0
    console.log( ! regex.test(str)) // 0, true, false
})(new RegExp("new", "gmi"), "new")

MDN

If lastIndex is equal to the length of the string and if the regular expression does not match the empty string, then the regular expression mismatches input, and lastIndex is reset to 0.

So, lastIndex is updated in case a global regex is used more than once and it decides where to start matching.

like image 31
Amit Joki Avatar answered Oct 03 '22 18:10

Amit Joki