Why does ++[[]][+[]]+[+[]] return the string "10"?

javascript, jsfuck, syntax

Solution

If we split it up, the mess is equal to:

++[[]][+[]]
+
[+[]]

In JavaScript, it is true that `+[] === 0`. `+` converts something into a number, and in this case it will come down to `+""` or `0` (see specification details below).

Therefore, we can simplify it (`++` has precendence over `+`):

++[[]][0]
+
[0]

Because `[[]][0]` means: get the first element from `[[]]`, it is true that:

`[[]][0]` returns the inner array (`[]`). Due to references it's wrong to say `[[]][0] === []`, but let's call the inner array `A` to avoid the wrong notation.

`++` before its operand means “increment by one and return the incremented result”. So `++[[]][0]` is equivalent to `Number(A) + 1` (or `+A + 1`).

Again, we can simplify the mess into something more legible. Let's substitute `[]` back for `A`:

(+[] + 1)
+
[0]

Before `+[]` can coerce the array into the number `0`, it needs to be coerced into a string first, which is `""`, again. Finally, `1` is added, which results in `1`.

- `(+[] + 1) === (+"" + 1)`

- `(+"" + 1) === (0 + 1)`

- `(0 + 1) === 1`

Let's simplify it even more:

1
+
[0]

Also, this is true in JavaScript: `[0] == "0"`, because it's joining an array with one element. Joining will concatenate the elements separated by `,`. With one element, you can deduce that this logic will result in the first element itself.

In this case, `+` sees two operands: a number and an array. It’s now trying to coerce the two into the same type. First, the array is coerced into the string `"0"`, next, the number is coerced into a string (`"1"`). Number `+` String `===` String.

"1" + "0" === "10" // Yay!

Specification details for `+[]`:

This is quite a maze, but to do `+[]`, first it is being converted to a string because that's what `+` says:

11.4.6 Unary + Operator

The unary + operator converts its operand to Number type.

The production UnaryExpression : + UnaryExpression is evaluated as follows:

Let expr be the result of evaluating UnaryExpression.

Return ToNumber(GetValue(expr)).

`ToNumber()` says:

Object

Apply the following steps:

Let primValue be ToPrimitive(input argument, hint String).

Return ToString(primValue).

`ToPrimitive()` says:

Object

Return a default value for the Object. The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType. The behaviour of the [[DefaultValue]] internal method is defined by this specification for all native ECMAScript objects in 8.12.8.

`[[DefaultValue]]` says:

8.12.8 [[DefaultValue]] (hint)

When the [[DefaultValue]] internal method of O is called with hint String, the following steps are taken:

Let toString be the result of calling the [[Get]] internal method of object O with argument "toString".

If IsCallable(toString) is true then,

a. Let str be the result of calling the [[Call]] internal method of toString, with O as the this value and an empty argument list.

b. If str is a primitive value, return str.

The `.toString` of an array says:

15.4.4.2 Array.prototype.toString ( )

When the toString method is called, the following steps are taken:

Let array be the result of calling ToObject on the this value.

Let func be the result of calling the [[Get]] internal method of array with argument "join".

If IsCallable(func) is false, then let func be the standard built-in method Object.prototype.toString (15.2.4.2).

Return the result of calling the [[Call]] internal method of func providing array as the this value and an empty arguments list.

So `+[]` comes down to `+""`, because `[].join() === ""`.

Again, the `+` is defined as:

11.4.6 Unary + Operator

The unary + operator converts its operand to Number type.

The production UnaryExpression : + UnaryExpression is evaluated as follows:

Let expr be the result of evaluating UnaryExpression.

Return ToNumber(GetValue(expr)).

`ToNumber` is defined for `""` as:

The MV of StringNumericLiteral ::: [empty] is 0.

So `+"" === 0`, and thus `+[] === 0`.

Problem

This is valid and returns the string `"10"` in JavaScript (more examples here): ``` console.log(++[[]][+[]]+[+[]]) ``` Why? What is happening here?

Original source

Related problems