284

The following shows that "0" is false in Javascript:

>>> "0" == false
true

>>> false == "0"
true

So why does the following print "ha"?

>>> if ("0") console.log("ha")
ha
nonopolarity
  • 146,324
  • 131
  • 460
  • 740
  • 62
    `"0"` is a string, and since it's not empty, it's evaluated to true. – Digital Plane Sep 30 '11 at 19:36
  • 10
    `"0" === false [...] false` –  Sep 30 '11 at 19:36
  • 3
    Check out Angus Croll's article truth in javascript. http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/ – timrwood Sep 30 '11 at 20:25
  • 9
    `'0'==false` but '0' is not a falsey value (yes Javascript can be weird) – Linsey Sep 30 '11 at 23:25
  • 7
    @Linsey: The whole "falsy" and "truthy" thing was only ever meant to explain how values are converted to booleans. When you compare two values with `==`, they **never** get converted to booleans, so it doesn't apply. (The rules for the conversion seem to favour converting to numbers.) – millimoose Oct 01 '11 at 00:56
  • `== false` and `== true` are fundamentally wrong things to do. – hobbs Oct 06 '11 at 23:48
  • 1
    related: [Why does !!1==“1” equal true and !!2==“2” equal false?](http://stackoverflow.com/q/23693089/1048572) – Bergi May 27 '14 at 14:56
  • `==` is generally Considered Harmful in JavaScript; see [this answer](http://stackoverflow.com/a/359509/1168116) for more. – Malcolm Mar 11 '16 at 22:20

15 Answers15

425

Tables displaying the issue:

truthy if statement

and == truthy comparisons of all object types in javascript

Moral of the story use === strict equality displaying sanity

table generation credit: https://github.com/dorey/JavaScript-Equality-Table

Joe
  • 80,724
  • 18
  • 127
  • 145
  • 2
    It makes much more sense with another order of values https://gist.github.com/kirilloid/8165660 – kirilloid Dec 28 '13 at 23:33
  • 3
    From now on, if someone says that he never uses strict comparison operators, I will face him with these tables and make him cry. Still not sure if I grasp the concept of `NaN` though. I mean, `typeof NaN // number` but `NaN === NaN // false`, hmm... – Justus Romijn Nov 19 '14 at 10:06
  • 4
    A friend of mine made http://f.cl.ly/items/3b0q1n0o1m142P1P340P/javascript_equality.html - the same graphs as above, but a bit easier to read. – Lucy Bain Dec 17 '14 at 22:50
  • @JustusRomijn there are multiple values to represent `NaN`, so when you are comparing 2 NaNs, they are of different values (I guess). Read the first quote [here](http://stackoverflow.com/a/18069733/278405#get-the-number-18437736874454810627). – cychoi May 31 '15 at 09:54
  • This is really useful. And when i look at the table for ==, i once more know why i avoid that kind of comparison completely forever. – Hinrich Jul 02 '15 at 09:49
  • 5
    These tables have a mistake. Neither `==` nor `===` operator for the `[]`, `{}`, `[[]]`, `[0]` and `[1]` values do not evaluate to true. I mean `[] == []` and `[] === []` also false. – Herbertusz Sep 07 '15 at 08:46
  • Herbertusz: not necessarily. I think the chart is implying that the comparison is performed on the same object in those cases, like `var foo = []; if(foo === foo);`, etc. – Taywee Nov 16 '15 at 19:48
  • unified table https://dorey.github.io/JavaScript-Equality-Table/unified/ – Abdul Rauf Jun 06 '18 at 07:38
  • That lower right corner is now green if you use `Object.is()`. Check out [my answer](https://stackoverflow.com/a/12628417/1195056) about how to determine if `NaN` is equal to `NaN`. – krillgar Jul 31 '19 at 11:29
294

The reason is because when you explicitly do "0" == false, both sides are being converted to numbers, and then the comparison is performed.

When you do: if ("0") console.log("ha"), the string value is being tested. Any non-empty string is true, while an empty string is false.

Equal (==)

If the two operands are not of the same type, JavaScript converts the operands then applies strict comparison. If either operand is a number or a boolean, the operands are converted to numbers if possible; else if either operand is a string, the other operand is converted to a string if possible. If both operands are objects, then JavaScript compares internal references which are equal when operands refer to the same object in memory.

(From Comparison Operators in Mozilla Developer Network)

Zearin
  • 1,474
  • 2
  • 17
  • 36
jdi
  • 90,542
  • 19
  • 167
  • 203
44

It's according to spec.

12.5 The if Statement 
.....

2. If ToBoolean(GetValue(exprRef)) is true, then 
a. Return the result of evaluating the first Statement. 
3. Else, 
....

ToBoolean, according to the spec, is

The abstract operation ToBoolean converts its argument to a value of type Boolean according to Table 11:

And that table says this about strings:

enter image description here

The result is false if the argument is the empty String (its length is zero); otherwise the result is true

Now, to explain why "0" == false you should read the equality operator, which states it gets its value from the abstract operation GetValue(lref) matches the same for the right-side.

Which describes this relevant part as:

if IsPropertyReference(V), then 
a. If HasPrimitiveBase(V) is false, then let get be the [[Get]] internal method of base, otherwise let get
be the special [[Get]] internal method defined below. 
b. Return the result of calling the get internal method using base as its this value, and passing 
GetReferencedName(V) for the argument

Or in other words, a string has a primitive base, which calls back the internal get method and ends up looking false.

If you want to evaluate things using the GetValue operation use ==, if you want to evaluate using the ToBoolean, use === (also known as the "strict" equality operator)

NullUserException
  • 83,810
  • 28
  • 209
  • 234
Incognito
  • 20,537
  • 15
  • 80
  • 120
  • `"a string has a primitive base, which calls back the internal get method and ends up looking false"` Is this true for all strings ? – aziz punjani Sep 30 '11 at 20:26
  • @Interstellar_Coder `Section 8.12.3: [[Get]] (P)` describes how it works. It's true only for cases that string are 0, as it does a bunch of other internal calls eventually resulting in `GetOwnProperty` which sees that "whatever" is a data property, which then returns all the way back that value. This is why "0" is false, and "blah" is true. Check out some of Douglas Crockford's videos on Yahoo developer theater, he describes "truthyness" in JavaScript a little less complex than I am. If you understand what "truthy" and "falsy" means you'll understand Bobince's answer right away. – Incognito Sep 30 '11 at 20:46
  • 1
    Where can I find the spec? – user985366 Jun 14 '16 at 13:32
13

It's PHP where the string "0" is falsy (false-when-used-in-boolean-context). In JavaScript, all non-empty strings are truthy.

The trick is that == against a boolean doesn't evaluate in a boolean context, it converts to number, and in the case of strings that's done by parsing as decimal. So you get Number 0 instead of the truthiness boolean true.

This is a really poor bit of language design and it's one of the reasons we try not to use the unfortunate == operator. Use === instead.

bobince
  • 528,062
  • 107
  • 651
  • 834
8
// I usually do this:

x = "0" ;

if (!!+x) console.log('I am true');
else      console.log('I am false');

// Essentially converting string to integer and then boolean.
Thava
  • 1,597
  • 17
  • 13
8

Your quotes around the 0 make it a string, which is evaluated as true.

Remove the quotes and it should work.

if (0) console.log("ha") 
Jason Gennaro
  • 34,535
  • 8
  • 65
  • 86
  • 2
    correct, not about how to "make it work" but the question is more like, "why it behaved that way?" – nonopolarity Oct 21 '14 at 23:51
  • It's funny that after all these years the correct answer is sitting right here yet so few people notice. @JasonGennaro, thank you for not overlooking the obvious. – davidhartman00 Apr 21 '21 at 16:58
2

== Equality operator evaluates the arguments after converting them to numbers. So string zero "0" is converted to Number data type and boolean false is converted to Number 0. So

"0" == false // true

Same applies to `

false == "0" //true

=== Strict equality check evaluates the arguments with the original data type

"0" === false // false, because "0" is a string and false is boolean

Same applies to

false === "0" // false

In

if("0") console.log("ha");

The String "0" is not comparing with any arguments, and string is a true value until or unless it is compared with any arguments. It is exactly like

if(true) console.log("ha");

But

if (0) console.log("ha"); // empty console line, because 0 is false

`

2

This is because JavaScript uses type coercion in Boolean contexts and your code

if ("0") 

will be coerced to true in boolean contexts.

There are other truthy values in Javascript which will be coerced to true in boolean contexts, and thus execute the if block are:-

if (true)
if ({})
if ([])
if (42)
if ("0")
if ("false")
if (new Date())
if (-42)
if (12n)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)

Sachin
  • 1,206
  • 12
  • 13
2

This is the reason why you should whenever possible use strict equality === or strict inequality !==

"100" == 100

true because this only checks value, not the data type

"100" === 100

false this checks value and data type

Boken
  • 4,825
  • 10
  • 32
  • 42
2

It is all because of the ECMA specs ... "0" == false because of the rules specified here http://ecma262-5.com/ELS5_HTML.htm#Section_11.9.3 ...And if ('0') evaluates to true because of the rules specified here http://ecma262-5.com/ELS5_HTML.htm#Section_12.5

Narendra Yadala
  • 9,554
  • 1
  • 28
  • 43
1

The "if" expression tests for truthiness, while the double-equal tests for type-independent equivalency. A string is always truthy, as others here have pointed out. If the double-equal were testing both of its operands for truthiness and then comparing the results, then you'd get the outcome you were intuitively assuming, i.e. ("0" == true) === true. As Doug Crockford says in his excellent JavaScript: the Good Parts, "the rules by which [== coerces the types of its operands] are complicated and unmemorable.... The lack of transitivity is alarming." It suffices to say that one of the operands is type-coerced to match the other, and that "0" ends up being interpreted as a numeric zero, which is in turn equivalent to false when coerced to boolean (or false is equivalent to zero when coerced to a number).

Jollymorphic
  • 3,510
  • 16
  • 16
0

I have same issue, I found a working solution as below:

The reason is

    if (0) means false, if (-1, or any other number than 0) means true. following value are not truthy, null, undefined, 0, ""empty string, false, NaN

never use number type like id as

      if (id) {}

for id type with possible value 0, we can not use if (id) {}, because if (0) will means false, invalid, which we want it means valid as true id number.

So for id type, we must use following:

   if ((Id !== undefined) && (Id !== null) && (Id !== "")){
                                                                                
                                                                            } else {

                                                                            }
                                                                            

for other string type, we can use if (string) {}, because null, undefined, empty string all will evaluate at false, which is correct.

       if (string_type_variable) { }
hoogw
  • 4,982
  • 1
  • 37
  • 33
0

In JS "==" sign does not check the type of variable. Therefore, "0" = 0 = false (in JS 0 = false) and will return true in this case, but if you use "===" the result will be false.

When you use "if", it will be "false" in the following case:

[0, false, '', null, undefined, NaN] // null = undefined, 0 = false

So

if("0") = if( ("0" !== 0) && ("0" !== false) && ("0" !== "") && ("0" !== null) && ("0" !== undefined) && ("0" !== NaN) )
        = if(true && true && true && true && true && true)
        = if(true)
vtc
  • 66
  • 5
0

I came here from search looking for a solution to evaluating "0" as a boolean. The technicalities are explained above so I won't go into it but I found a quick type cast solves it.

So if anyone else like me is looking to evaluate a string 1 or 0 as boolean much like PHP. Then you could do some of the above or you could use parseInt() like:

x = "0";
if(parseInt(x))
//false
Abu Nooh
  • 846
  • 4
  • 12
  • 42
0
if (x) 

coerces x using JavaScript's internal toBoolean (http://es5.github.com/#x9.2)

x == false

coerces both sides using internal toNumber coercion (http://es5.github.com/#x9.3) or toPrimitive for objects (http://es5.github.com/#x9.1)

For full details see http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/

AngusC
  • 628
  • 5
  • 9