Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If an array is truthy in JavaScript, why doesn't it equal true?

I have the following code snippet:

if([]) {
  console.log("first is true");
}

The console says first is true which means [] is true. Now I am wondering why this:

if([] == true) {
  console.log("second is true");
}

and this:

if([] === true) {
  console.log("third is true");
}

are not true. If the console logged first is true in the first snippet, that means [] should be true, right? So why do the latter two comparisons fail? Here is the fiddle.

like image 924
zuluk Avatar asked Jun 14 '17 16:06

zuluk


2 Answers

This is by specification. By the ECMAScript 2015 Language Specification, any object that is implicitly coerced into a boolean is true; that means objects are truthy. Inside of an if statement, the condition, once evaluated and if not already boolean, is coerced into a boolean. Thus, doing:

if([]) { 
  ... 
}

[] is truthy when coerced to a boolean and is true.

On the other hand, when you try to compare two values of differing types with abstract comparison, ==, the engine must internally go through an algorithm to reduce the values to similar types, and ultimately integers that it can compare. In Section 7.2.12 of the specification on the steps for Abstract Equality Comparison x == y, it states:

7.2.12 Abstract Equality Comparison

The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:

[...]

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

Thus, the y operand (in this case true) is converted to 1 by coercion with ToNumber since it is a boolean, and [] == 1 is false because:

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

This will convert the x operand to a string with the toString method of the array, which is "" for an empty array in this case. After going through ToPrimitive, it will result in:

if("" == 1) {
  ...
}

And finally:

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

Thus, ToNumber of an empty string "" is 0 and you get:

if(0 == 1) {
  ...
}

And 0 does not equal 1, thus it is false. Remember that just because something is truthy, does not make it equal to true. Just try Symbol() == true or ({}) == true.

The final comparison, with === is strict comparison, and does not coerce any operands and will return false if both operands are not the same type. Since the left operand is an object (an array) and the right is a number, the comparison evaluates to false.

like image 152
Andrew Li Avatar answered Nov 11 '22 01:11

Andrew Li


You have force type coercion before making a Boolean equity check with the Object types.

while "" == false // <- true or 0 == false // <- true works out well

with the Object types it doesn't

null == false // <- false

so you better do like

!!null === false // <- true or !![] === true // <- true

like image 1
Redu Avatar answered Nov 11 '22 03:11

Redu