3

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?

Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111
Thomaz Capra
  • 985
  • 9
  • 21

3 Answers3

5

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.

Rosmarine Popcorn
  • 10,761
  • 11
  • 59
  • 89
  • FWIW, `! + [1,2,3]` is `true`. `!` is an operator, not a value. – Felix Kling Jan 14 '19 at 21:20
  • @FelixKling you're right about the first sentence. As for the other one, once ! is brought in a boolean context I think you can see it as a value from that perspective. – Rosmarine Popcorn Jan 14 '19 at 22:13
  • 2
    *"you can see it as a value from that perspective"* No. Operators are not values, the *operate on* values. I only mentioned this because your example seemed to imply that `!` is converted to `false`. – Felix Kling Jan 14 '19 at 22:29
  • I feel this answer misses the point that `!` is acting on the Number returned by unary plus `+[]` and rather implies that `!` in itself can be used as a value that would be part of an operation `x + y` if `+` were the addition operator. This is not what happens. the first line would be more `(! (+[])) + []` which is equivalent to `!0 + []`. – Kaiido Jan 15 '19 at 03:08
3

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.

Shidersz
  • 16,846
  • 2
  • 23
  • 48
2

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.

crashmstr
  • 28,043
  • 9
  • 61
  • 79
  • 1
    What do you mean with `that these are not arrays but strings`? `[]` are indeed Arrays, but those arrays are converted to Strings. – t.niese Jan 14 '19 at 21:19
  • @t.niese "these" refers to `v` (`true`) and `c` (`false`), not the operands to `+`. – crashmstr Jan 15 '19 at 20:59