Почему использование унарного оператора + в массиве дает противоречивые результаты в javascript?

Я тестировал преобразование значений в целое число в javascript и печатал вывод в консоли, когда сталкивался с этим странным поведением.

console.log(+[]) ==> 0
console.log(+[123]) ==> 123
console.log(+['123']) ==> 123
console.log(+[123, 456]) ==> NaN
console.log(+['123asdf']) ==> NaN

Я думал, что значения были преобразованы с помощью parseInt, но оказалось, что это было не так. Я перешел в таблицу преобразования javascript http://www.w3schools.com/js/js_type_conversion.asp

Это дает мне более полное представление о том, как выполняются преобразования. В соответствии с этой таблицей

[] => 0
[20] => 20
[10,20] => NaN
["twenty"] =>NaN
["ten","twenty"] => NaN

Таким образом, они берут первое значение массива и преобразуют его, используя указанные правила. Правила parseInt не применяются.

Я протестировал, чтобы прийти к такому выводу. Вы можете вложить в нее все, что хотите, это даст вам тот же результат.

console.log(+[[[[[[[[[[[10]]]]]]]]]]]) => 10

Итак, тогда я подумал, хорошо, если это случай

console.log(+[undefined]) will return NaN
console.log(+[null]) will return 0
console.log(+[false]) will return 0

это значения, ожидаемые от таблицы преобразования javascript, до целого числа, но оказываются

console.log(+[undefined]) => 0
console.log(+[null]) => 0
console.log(+[false]) => NaN

Последнее самое странное, потому что false преобразуется в 0, а не в NaN. Может ли кто-нибудь объяснить странное поведение или объяснить, как это преобразование выполняется?

Ответ 1

Оператор Unary + использует абстрактную операцию ToNumber.

абстрактная операция ToNumber, когда применяется к объектам, вызывает метод toString объекта (посредством [[DefaultValue]] внутренний метод), а затем повторно применяет операцию ToNumber в результирующем строчном представлении.

Интересным здесь является метод Array toString. Обратите внимание, что [false].toString() сильно отличается от [undefined].toString() или [null].toString(). Когда мы проверяем спецификацию Array.prototype.toString, мы видим, что внутри она использует Array.prototype.join. Шаг 8 алгоритма join гласит:

  1. Если element0 является undefined или null, пусть R - пустая строка; в противном случае пусть R - ToString (element0).

Таким образом, любой массив, содержащий один null или undefined, строит на пустую строку (номер ToNumber - ifies на 0), в то время как другие значения будут привязаны к какой-либо другой строке (которая будет затем number-ify до NaN, если строка не является числовой).

+[undefined] совпадает с +"", а +[false] совпадает с +"false".