Thomaz Capra
Thomaz Capra

Reputation: 1063

Why (!+[]+[]) is 'true' and (false + []) is 'false' in Javascript?

I'm looking at ECMA-262 grammar for a definition of the next code bellow:

const v = (! + [] + []);
const c = (false + []);

console.log(v);
console.log(c);

What is BEHIND it?

Until now I did not find anything helpful, does anyone know why it gives those results or have references about it?

Upvotes: 3

Views: 297

Answers (3)

Rosmarine Popcorn
Rosmarine Popcorn

Reputation: 10967

This is because when you try to apply an operator to different data structure JavaScript engine applies coercion.

In the first case what it does is :

  1. Convert first [] to primitive, which is performed by invoking toString() method of array. The toString method joins all the array values to a string. If you wold have something like (false + [1,2,3]) you would get : false1,2,3

  2. The second step is to bring the boolean in the String context

  3. Now that we have all the values in the same datastructure, it will simply concatenate all of them

In your case (! + [] + []) is evaluated to 'true' which has the length of 4.

The book You Don't Know JS: Types & Grammar is a gem for understanding all these kind of weird operations JavaScript engine does.

EDIT: As Felix Kling was suggesting ! operator has a different role in the evaluation of (! + [] + []).

In this case what happens is that :

  • ! + [] is evaluated to true. This is because ! + [] puts them in a Boolean context where [toNumber] operation is applied on [] which is 0 and !0 is true

  • true + [] is evaluated to 'true'. This is because when you try to add a boolean with an object (array is derived from object) [toString] operation is applied to both items.

Upvotes: 5

crashmstr
crashmstr

Reputation: 28573

const v = (! + [] + []);
const c = (false + []);

console.log(v);
console.log(c);

If you take out the .length, you see that the results are: true and false and that these (the results of the + operations) are not arrays but strings, and true is 4 characters long and false is 5.

Using your link above, it looks like this is at least partly relevant:

12.7.3 The Addition operator ( + )

NOTE The addition operator either performs string concatenation or numeric addition.

Upvotes: 2

Shidersz
Shidersz

Reputation: 17190

Actually, for understand why you are getting that result, you have to think how the expression is evaluated (i.e, in what order?). If we observe your first expression:

const v = (! + [] + []);

we can see that there exists one logical operator (the logical NOT !), one unary operator (+) and one arithmetic operator, actually the addition +. If we take into account the order of evaluation of that expression, we can write it like this:

const v = ( (!(+[])) + [] );

Now, the first expression evaluated here is +[], and from the documentation of the unary plus operator you get:

The unary plus operator precedes its operand and evaluates to its operand but attempts to convert it into a number, if it isn't already...

Actually, the previous evaluation results in 0 (a coercion occurs in where the empty array is casted to number type) as you can check on next example:

console.log(+[]);

So now, the expression is reduced to

const v = ( (!0) + [] );

Again, reading some documentation of this logical not operator you can found:

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

So, !0 is reduced to true (another coercion occurs in where the number zero is casted to boolean type) as you can check on next example:

console.log(!0);

Now, we have next expression where the addition operator comes into play:

const v = ( true + [] );

The addition operator produces the sum of numeric operands or string concatenation.

In this case, the operator will do string concatenation since the operands aren't numbers. So, here is where a new coercion (basically a implicit cast of types) takes places again, because it need to convert both of the operand to strings:

  • true is converted to string "true" using the method toString() of the Boolean type.
  • and the empty array [] is converted to the empty string "" using the available toString() method of Array type.

And finally, our expression is reduce to:

const v = "true" + ""; // or simply "true".

const v = (! + [] + []);
console.log("value: " + v, "type: " + typeof(v));

The second expression should be easy to analyze for your own now, since it is a simplified version of the first one.

Upvotes: 3

Related Questions