WTF JS
[] + []

""

[] + {} [object Object]
{} + []

0

{} + {}

[object Object][object Object] (Node/Chrome)
...or NaN (Firefox)

Array(10)

,,,,,,,,,

Array(10).join('wat')

watwatwatwatwatwatwatwatwatwat

Array(10).join('wat' + 1)

wat1wat1wat1wat1wat1wat1wat1wat1wat1wat1

Array(10).join('wat'-1) + " Batman!"

NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN Batman!

What happens?

  • GetValue called on both sides of +
  • ToPrimitive called after
  • GetValue + ToPrimitive => toString() then concatenate

Explanation : [] + []

```js [].toString() = '' ```
```js ToPrimitive(GetValue(([])) + ToPrimitive(GetValue(([])) = ToPrimitive([]) + ToPrimitive([]) = [].toString() + [].toString() = '' + '' = '' ```

Explanation : [] + {}

  • Object.prototype.toString() => '[object ' + class + ']'
  • class => {}.constructor.name => 'Object'
```js ToPrimitive(GetValue(([])) + ToPrimitive(GetValue(({})) = ToPrimitive([]) + ToPrimitive({}) = [].toString() + {}.toString() = '' + '[object Object]' = '[object Object]' ```

Explanation : {} + {} (Node/Chrome)

```js ToPrimitive(GetValue(({})) + ToPrimitive(GetValue(({})) = ToPrimitive({}) + ToPrimitive({}) = {}.toString() + {}.toString() = '[object Object]' + '[object Object]' = '[object Object][object Object]' ```

Explanation : {} + {} (Firefox)

  • {} + {} => +{} (first {} considered as a code block)
  • ToNumber()
  • number => number
  • empty string => 0
  • truthy and falsy values => 1 and 0
  • anything else => NaN

Explanation : {} + {} (Firefox)

```js +ToNumber(ToPrimitive(GetValue({}))) = +ToNumber(ToPrimitive({})) = +ToNumber({}.toString()) = ToNumber('[object Object]') = NaN ```

Explanation : {} + []

```js +ToNumber(ToPrimitive(GetValue([]))) = +ToNumber(ToPrimitive([])) = +ToNumber([].toString()) = ToNumber('') = 0 ```

Explanation : Batman

  • Array(10) => Array of 10 elements
  • Then we append 'wat' => [1,2,3].join('hi') => 1hi2hi3
  • Then we concatenate ' Batman!'
  • 'wat' — 1 => NaN
  • => Batman

Links