3

Was just doing some testing and I find this odd:

[] == false

Gives true, this makes sense because double equal only compares contents and not type and tries to do type-coercion. But if its comparing contents and returns true, that means [ ] is falsey (if you did [] == true you get false too), which means:

[] || false

Should give false, but it gives [ ], making it truthy? Why?

Another example:

"\n  " == 0

Gives true, but "\n " || false gives "\n "? Is there an explanation for this or its just an oddity.

When I tried this in C, we get:

int x = "\n " == 0;
printf("%d\n", x);

int y = "\n " || 0;
printf("%d\n", y);

Outputs:

0
1

This makes sense, but given C's influence on Javascript, the behaviour is different.

user2864740
  • 60,010
  • 15
  • 145
  • 220
olive_tree
  • 1,417
  • 16
  • 23
  • 1
    `[]` is a *truthy* expression, but `==` performs *coercions*. The rules are covered in [11.9.3 The Abstract Equality Comparison Algorithm](http://es5.github.io/#x11.9.3) (searching for ["Equality Comparison Algorithm"](http://stackoverflow.com/search?q=%5Bjavascript%5D+%22Equality+Comparison+Algorithm%22) will likely find relevant questions). – user2864740 Aug 12 '14 at 19:44
  • See this WTF JS: [All your commas are belong to Array](http://wtfjs.com/2011/02/11/all-your-commas-are-belong-to-Array) – Greg Burghardt Aug 12 '14 at 19:47

3 Answers3

4

Type conversion is not related to falsy and truthy values.

What is truthy and what is falsy is defined by the ToBoolean function defined in the specs and [] is indeed truthy.

On the other hand, [] == false returns true because of the type conversion that happens during the evaluation of the expression.

The rules of type conversion say that for x == y

If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).

ToNumber results in 0 for false so we're left with the evaluation of [] == 0. According to the same rules

If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.

ToPrimitive results in an empty string. Now we have "" == 0. Back to our type conversion rules

If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.

ToNumber results in 0 for "" so the final evaluation is 0 == 0 and that is true!

dee-see
  • 23,668
  • 5
  • 58
  • 91
  • there is no ToBoolean() in JS, so type conversions are often converted to boolean if a better match is not found. if it can compare as a string or number, it will prefer that before stooping to true/false. – dandavis Aug 12 '14 at 20:19
  • @dandavis `ToBoolean` as defined by the spec as I said. It's a function used by the JS interpreter, not a JS function – dee-see Aug 12 '14 at 20:20
  • ok, you're right, but how does that explain why [] is converted to a string to compare to false? – dandavis Aug 12 '14 at 20:27
  • @dandavis It's all in the links I gave but I edited a complete explanation in my answer. – dee-see Aug 12 '14 at 20:35
  • @dandavis Glad you appreciate! – dee-see Aug 12 '14 at 20:37
3

"Is false" (even with coercion) is different from "evaluates as false in boolean context." obj == false asks if the object is the boolean value false, not whether it would evaluate as such if evaluated in boolean context.

You can evaluate an object in boolean context with (!!obj).

[] == false;         // true
(!![]) == false;     // false

"\n  " == false;     // true
(!!"\n  ") == false; // false
cdhowie
  • 158,093
  • 24
  • 286
  • 300
0

from the ECMA-262 5.1 (page 83):

If ToBoolean(lval) is true, return lval

[] || false; // []
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392