Вместо того, чтобы просто повторить результат, который вы продемонстрировали в этом вопросе, я попытаюсь дать описание почему вы получаете этот результат.
Объяснение
Взяв только первый пример (поскольку остальные будут делать что-то похожее), мы можем следовать спецификации, чтобы увидеть, что происходит.
Из 11.4.6 Унарный + Оператор , мы можем видеть, что происходит преобразование ToNumber
.
Return ToNumber (GetValue (expr)).
С 9.3 ToNumber мы видим, что если дан объект (например, ваш массив), происходит преобразование ToPrimitive
с последующей попыткой ToNumber
.
Object
Примените следующие шаги:
- Пусть primValue будет ToPrimitive (входной аргумент, номер подсказки).
- Return ToNumber (primValue).
Из 9.1 В Примитив , если ToPrimitive
получает Объект, мы можем видеть, что его [[DefaultValue]]
выбирается:
Объект
Возвращает значение по умолчанию для объекта. Значение объекта по умолчанию извлекается путем вызова внутреннего метода [[DefaultValue]] объекта, передавая необязательную подсказку PreferredType. Поведение внутреннего метода [[DefaultValue]] определяется этой спецификацией для всех собственных объектов ECMAScript в 8.12.8.
Начиная с 8.12.8 [[DefaultValue]] (подсказка) , в конечном итоге произойдет то, что toString()
будет вызываться в массиве и возвращаться. Эта строка отправляется на рекурсив ToNumber
, как описано выше.
Так что же происходит, когда ToNumber
преобразование выполняется для строки? Ну, это описано в 9.3.1 ToNumber, применяемый к типу строки , и немного длиннее. Проще просто сделать преобразование напрямую и посмотреть, что произойдет:
Number(""); // result is 0 on an empty string
Number(" "); // result is 0 on a string with only whitespace
Number("123"); // result is 123 on a numeric string
Number(" 123 ");// result is 123 on a numeric string with leading & trailing spaces
Number("abc"); // result is NaN (not a number) on non-numeric strings
Итак, вопрос в том, какую строку мы получаем из нашего массива. Опять же, это легко проверить.
[].toString(); // result is "" (empty string)
Поскольку результатом является пустая строка, а ToNumber
преобразование пустой строки равно 0
, как показано выше, это будет означать, что мы сравниваем 0 === 0
.
Это было бы так же, как если бы мы сделали:
Number( [].toString() ) === 0; // true
Или нарисовать немного больше:
var x = [];
x = x.toString(); // ""
x = Number( x ); // 0
x === 0; // true
Подробнее toString
Результаты.
Чтобы показать больше toString
преобразований массивов, рассмотрим следующее:
[1].toString(); // "1"
[1,2,3].toString(); // "1,2,3"
["a",1,"b",2].toString(); // "a,1,b,2"
Таким образом, чтобы выполнить преобразование ToNumber
на вышеуказанных массивах, первое даст нам число, а два последних приведут к NaN
.
Number([1]); // 1
Number([1,2,3]); // NaN
Number(["a",1,"b",2]); // NaN
Некоторые доказательства
Чтобы еще раз подтвердить, что это преобразование toString()
происходит до преобразования ToNumber
, мы можем фактически изменить Array.prototype.toString
, чтобы получить другой результат, и любые преобразования ToNumber
будут использовать этот измененный результат.
Array.prototype.toString = function() {
var n = 0;
for( var i = 0; i < this.length; i++ ) {
n += this[i];
}
return n;
};
Здесь я заменил toString
на Array.prototype
функцией, которая суммирует массив. Очевидно, вы не хотите этого делать, но мы можем показать, как теперь мы получим другой результат.
Number([1,2,3]); // 6
+[1,2,3]; // 6
Итак, теперь вы можете видеть, что преобразование ToNumber
нашего массива, которое раньше приводило к NaN
, теперь приводит к сумме элементов в массиве.