Мы можем ссылаться на спецификацию, и это замечательно и точно, но большинство случаев также можно объяснить более понятным образом со следующими утверждениями:
+
и -
работают только с примитивными значениями. Более конкретно +
(дополнение) работает с любыми строками или числами, а +
(унарный) и -
(вычитание и унарный) работает только с числами. valueOf
или toString
, которые доступны для любого объекта. Вот почему такие функции или операторы не вызывают ошибок при вызове на объекты. Таким образом, мы можем сказать, что:
[] + []
как String([]) + String([])
, который аналогичен '' + ''
. Я упомянул выше, что +
(дополнение) также справедливо для чисел, но в JavaScript нет допустимого числа в массиве, поэтому вместо этого используется добавление строк. [] + {}
такое же, как String([]) + String({})
, который аналогичен '' + '[object Object]'
{} + []
. Это заслуживает большего объяснения (см. Ответ Вентеро). В этом случае фигурные скобки обрабатываются не как объект, а как пустой блок, поэтому он оказывается таким же, как +[]
. Unary +
работает только с числами, поэтому реализация пытается получить номер из []
. Сначала он пытается valueOf
, который в случае массивов возвращает один и тот же объект, поэтому он пытается использовать последнее средство: преобразование результата toString
в число. Мы можем записать его как +Number(String([]))
, который аналогичен +Number('')
, который аналогичен +0
. Array(16).join("wat" - 1)
вычитание -
работает только с числами, поэтому это то же самое, что: Array(16).join(Number("wat") - 1)
, поскольку "wat"
не может быть преобразовано в действительное число. Мы получаем NaN
, и любая арифметическая операция на NaN
получается с NaN
, поэтому мы имеем: Array(16).join(NaN)
.