16

I am now confused about ! operator in JavaScript. My understanding was ! operator operates only on boolean. But a comment to one of my answers says it can operate on anything and returns a boolean, which happened to be true after I did some tests.

alert(!undefined); //true
alert(!function(){}); //false
alert(!{}); //false
alert(!null); //true
alert(!()); //crash
alert(!"false"); //false
alert(!false)​;​​​​​​​​​​​​ //true​​​​​​​​​​​​​​​​​​

Can somebody help me generalize the behavior of ! operator.

EDIT

Even more confusing stuff:

​alert( new String() == ""); //true
alert(!""); //true
alert(! new String()); //false

How? ​

Community
  • 1
  • 1
hrishikeshp19
  • 8,838
  • 26
  • 78
  • 141
  • 17
    Welcome to javascript. If you are coming from a world of strong typing you are walking on uncharted territory. – Darin Dimitrov May 22 '12 at 21:57
  • 1
    JavaScript will implicitly convert those types to a boolean. – helpermethod May 22 '12 at 22:03
  • 1
    somewhat in relation to this, you might be interesting in my question about the differences between null and undefined in js http://stackoverflow.com/questions/7000762/null-vs-undefined-and-their-behaviour-in-javascript – Endophage May 22 '12 at 22:28

5 Answers5

20

! does what you think: turns true to false and vice-versa. The weird behavior has to do with how Javascript can convert literally anything to true or false.

http://11heavens.com/falsy-and-truthy-in-javascript

Like in C (only worse) all values can be promoted to true or false. The googlable terms you want are "truthy" and "falsy," or "truthiness" and "falsiness." Truthy means something converts to true, falsy means something converts to false. All values are truthy except null, undefined, 0, "", NaN, and... false

This link has more fun examples:

http://www.sitepoint.com/javascript-truthy-falsy/

And this site really likes doing pathological things with the funny behavior here:

http://wtfjs.com

Also note that == really tries hard to make things comparable whereas === just returns false if the things aren't comparable. Crockford in Javascript: The Good Parts recommends not using == entirely.

djechlin
  • 59,258
  • 35
  • 162
  • 290
  • thanks for the link...but that does not really answer my question...actually I wanted to ask how is ! operator defined in JavaScript. – hrishikeshp19 May 22 '12 at 22:02
  • 2
    Right, but you asked the wrong question. `!` does exactly what you think, it turns true to false and vice versa. The weird behavior you've seen has more to do with the weird truthiness of the things you're applying ! to. – djechlin May 22 '12 at 22:03
  • the comment was before answer was edited...new answer is much better :) along with other answers it was helpful. Thanks :) – hrishikeshp19 May 22 '12 at 22:07
  • http://wtfjs.com seems to be dead. I am now very curious about the examples that used to be there :) – Wilt Feb 02 '17 at 22:03
8

This is not so much a function of ! as a function of what is or is not true in javascript. If you are familiar with casting, the coercing of a variable to a specific type, then the following should be reasonably clear to you.

! only operates on booleans. Therefore, any variable you apply it to that is not boolean is first coerced to be a boolean before applying !. To relate this to your examples:

Boolean(undefined) == false 

undefined is sort of like null in javascript (there are some differences but that's a different topic). It should make sense that the Boolean equivalent is false. undefined goes beyond just absence of value, it declares the variable you are trying to use doesn't even exist.

Boolean(function(){}) == true

Functions are objects in javascript. Even if it's empty, it still has some basic properties common to function objects and therefore its Boolean equivalent is true. It's not nothing so it's something.

Boolean({}) == true

Like an empty function, {} defines an empty object. However, it still has some properties common to objects in javascript. It simply has no custom properties.

Boolean(null) == false

As I mentioned for undefined, null is similar but not quite the same. It indicates the absence of value.

Boolean(()) // error

() on their own don't really mean anything. You need something between them to make the syntax correct so this has no bearing on your false/true question. () alone is simply a syntax error.

Boolean("false") == true

"false" is a string. Just because it contains the letters f,a,l,s,e does not make it the same as the Boolean value false. A non-empty string is something and therefore coerces to the Boolean true. Note strings are kind of special objects in that an empty string "" coerces to false but an empty object, {}, as mentioned, coerces to true.

Boolean(false) == false

This one should be clear. false is already a Boolean so casting it doesn't change its value. It's still false.

From that, you can see how applying ! to each case would give you the results you have seen.

For further reading, here's a pretty good article on type coercion in javascript

UPDATE:

In regards to your String questions. There is a different between a String object and a string literal (something surrounded by quotes). You can create a String object from a string literal but a literal is not automatically an object. The same is true of numbers in javascript. JS has a Number object but you will often define numeric literals. The behaviour of Number is consistent with what you've seen with String:

alert( new Number() == 0); //true
alert(!0); //true
alert(! new Number()); //false

However, as you astutely mentioned in your comment:

alert( new String() === ""); //false

As the types are not the same; object vs. literal.

In general, Boolean(some_object) will always evaluate to true but depending on the exact value, Boolean(some_literal) may evaluate to false.

ADDENDUM

Just because I shot myself in the foot earlier this week I thought this would be a useful piece of information to add. In most languages an empty array, [], will be coerced to false. However, in Javascript, arrays are objects so even the empty array coerces to true. One to watch out for. When switching between js and the various server side languages it's easy to make a slip up along the lines of if(!maybe_empty_array){...} which will never pass because maybe_empty_array will always coerce to true. Instead you should do if(maybe_empty_array.length){...}. If the array is empty its length is 0 which safely coerces to false.

Endophage
  • 21,038
  • 13
  • 59
  • 90
  • +1 Thanks for clarifying String stuff...it conforms with my new test new String() === "" returns false...so, my edit is not really valid. – hrishikeshp19 May 22 '12 at 22:22
  • @hrishikeshp19 ah yes, I should have mentioned `===`. That makes it clear that while they can be coerced to the same value, the types are not the same, hence `==` returns `true` but `===` returns false. – Endophage May 22 '12 at 22:25
  • 2
    Note that `new String() === new String()` also returns `false` because the operands are two different objects. – nnnnnn May 22 '12 at 22:33
  • 1
    @nnnnnn curiously, `new String() == new String()` also evaluates to `false`. I guess that's consistent with `NaN == NaN` evaluating to `false` but I'm not sure why it was done that way (that is, I understand why that's the result, I don't know who thought that was a sensible implementation and got it formalised in the spec) – Endophage May 22 '12 at 23:04
5

"Can somebody help me generalize the behavior of ! operator."

Sure. It returns false if its single operand can be converted to true; otherwise, returns true.

Any object (including an "empty" object, {}, or a function), any non-empty string, and any non-zero number can all be converted to true. On the other hand, null, undefined, an empty string and zero will all be converted to false. The ! operator then returns the opposite, hence the results you show in your question.

nnnnnn
  • 147,572
  • 30
  • 200
  • 241
  • 1
    @hrishikeshp19 - It is not defined, so it is true. – PitaJ May 22 '12 at 22:06
  • 1
    @PitaJ - No, `{}` is an object, and any object is truthy so `!{}` is false. – nnnnnn May 22 '12 at 22:08
  • Well...thanks, something JS makes me memorize...so an object converts to true with exceptions of "" (String object with value "") and primitives like undefined, null, and zero. – hrishikeshp19 May 22 '12 at 22:11
  • @nnnnnn if any object is truthy why is "" which is same as new String() a false? – hrishikeshp19 May 22 '12 at 22:12
  • because "" is an new string, and new string is a new string, when you make a new something, it will not be equal to the old something – PitaJ May 22 '12 at 22:18
  • @PitaJ Nonono..either you are wrong or I did not understand what you wanted to say...I find that new String() == "" => true but new String()==="" => false ...so my edit is not really a valid question. – hrishikeshp19 May 22 '12 at 22:27
  • 2
    Strings and string objects aren't quite the same thing in JS. (It's a bit like the difference between int and Integer in Java.) `typeof ""` is "string", while `typeof new String()` is "object". It's confusing, but strings are a value type but when you call string methods (e.g., `.substr()`) on them they get converted to objects. (Similarly you can call Number methods on numeric primitives, e.g., `123.123.toFixed(1)` returns `123.1`.) – nnnnnn May 22 '12 at 22:27
3

! returns false if its single operand can be converted to true, or if it is a non-boolean value:

!(x == y)
!"something" 

And true if its operand can be converted to false:

!(x > y)
Glauco Vinicius
  • 2,527
  • 3
  • 24
  • 37
0

Will be hard to write a more generalized explanation than this:

var arr = [0, "", false, null, undefined, NaN];

for(var i = 0; i < 6; i++){
    console.log(!(arr[i]));//always true
}

Any other values will produce false

ajax333221
  • 11,436
  • 16
  • 61
  • 95