|
| 1 | +### Why does ++[[]][+[]]+[+[]] return the string “10”? |
| 2 | + |
| 3 | +```js |
| 4 | +console.log(++[[]][+[]] + [+[]]) |
| 5 | +``` |
| 6 | + |
| 7 | +**Output is 10** |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +#### Explanation-1 |
| 12 | + |
| 13 | +If we split it up, the mess is equal to: |
| 14 | + |
| 15 | + ++[[]][+[]] |
| 16 | + + |
| 17 | + [+[]] |
| 18 | + |
| 19 | +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). |
| 20 | + |
| 21 | +Therefore, we can simplify it (`++` has precendence over `+`): |
| 22 | + |
| 23 | + ++[[]][0] |
| 24 | + + |
| 25 | + [0] |
| 26 | + |
| 27 | +Because `[[]][0]` means: get the first element from `[[]]`, it is true that: |
| 28 | + |
| 29 | +`[[]][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. |
| 30 | + |
| 31 | +`++` before its operand means “increment by one and return the incremented result”. So `++[[]][0]` is equivalent to `Number(A) + 1` (or `+A + 1`). |
| 32 | + |
| 33 | +Again, we can simplify the mess into something more legible. Let's substitute `[]` back for `A`: |
| 34 | + |
| 35 | + (+[] + 1) |
| 36 | + + |
| 37 | + [0] |
| 38 | + |
| 39 | +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`. |
| 40 | + |
| 41 | +- `(+[] + 1) === (+"" + 1)` |
| 42 | +- `(+"" + 1) === (0 + 1)` |
| 43 | +- `(0 + 1) === 1` |
| 44 | + |
| 45 | +Let's simplify it even more: |
| 46 | + |
| 47 | + 1 |
| 48 | + + |
| 49 | + [0] |
| 50 | + |
| 51 | +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. |
| 52 | + |
| 53 | +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_. |
| 54 | + |
| 55 | + "1" + "0" === "10" // Yay! |
| 56 | + |
| 57 | +--- |
| 58 | + |
| 59 | +Specification details for `+[]`: |
| 60 | + |
| 61 | +This is quite a maze, but to do `+[]`, first it is being converted to a string because that's what `+` says: |
| 62 | + |
| 63 | +> 11.4.6 Unary + Operator |
| 64 | +> |
| 65 | +> The unary + operator converts its operand to Number type. |
| 66 | +> |
| 67 | +> The production UnaryExpression : + UnaryExpression is evaluated as follows: |
| 68 | +> |
| 69 | +> 1. Let expr be the result of evaluating UnaryExpression. |
| 70 | +> |
| 71 | +> 2. Return ToNumber(GetValue(expr)). |
| 72 | +
|
| 73 | +`ToNumber()` says: |
| 74 | + |
| 75 | +> Object |
| 76 | +> |
| 77 | +> Apply the following steps: |
| 78 | +> |
| 79 | +> 1. Let primValue be ToPrimitive(input argument, hint String). |
| 80 | +> |
| 81 | +> 2. Return ToString(primValue). |
| 82 | +
|
| 83 | +`ToPrimitive()` says: |
| 84 | + |
| 85 | +> Object |
| 86 | +> |
| 87 | +> 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. |
| 88 | +
|
| 89 | +`[[DefaultValue]]` says: |
| 90 | + |
| 91 | +> 8.12.8 [[DefaultValue]](hint) |
| 92 | +> |
| 93 | +> When the [[DefaultValue]] internal method of O is called with hint String, the following steps are taken: |
| 94 | +> |
| 95 | +> 1. Let toString be the result of calling the [[Get]] internal method of object O with argument "toString". |
| 96 | +> |
| 97 | +> 2. If IsCallable(toString) is true then, |
| 98 | +> |
| 99 | +> 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. |
| 100 | +> |
| 101 | +> b. If str is a primitive value, return str. |
| 102 | +
|
| 103 | +The `.toString` of an array says: |
| 104 | + |
| 105 | +> 15.4.4.2 Array.prototype.toString ( ) |
| 106 | +> |
| 107 | +> When the toString method is called, the following steps are taken: |
| 108 | +> |
| 109 | +> 1. Let array be the result of calling ToObject on the this value. |
| 110 | +> |
| 111 | +> 2. Let func be the result of calling the [[Get]] internal method of array with argument "join". |
| 112 | +> |
| 113 | +> 3. If IsCallable(func) is false, then let func be the standard built-in method Object.prototype.toString (15.2.4.2). |
| 114 | +> |
| 115 | +> 4. Return the result of calling the [[Call]] internal method of func providing array as the this value and an empty arguments list. |
| 116 | +
|
| 117 | +So `+[]` comes down to `+""`, because `[].join() === ""`. |
| 118 | + |
| 119 | +Again, the `+` is defined as: |
| 120 | + |
| 121 | +> 11.4.6 Unary + Operator |
| 122 | +> |
| 123 | +> The unary + operator converts its operand to Number type. |
| 124 | +> |
| 125 | +> The production UnaryExpression : + UnaryExpression is evaluated as follows: |
| 126 | +> |
| 127 | +> 1. Let expr be the result of evaluating UnaryExpression. |
| 128 | +> |
| 129 | +> 2. Return ToNumber(GetValue(expr)). |
| 130 | +
|
| 131 | +`ToNumber` is defined for `""` as: |
| 132 | + |
| 133 | +> The MV of StringNumericLiteral ::: [empty] is 0. |
| 134 | +
|
| 135 | +So `+"" === 0`, and thus `+[] === 0`. |
| 136 | + |
| 137 | +--- |
0 commit comments