Почему сложение числа с массивом выдает строку?
Как видно из примера ниже, массив и число складываются как строки.
console.log([5] + 25); //525
Почему так происходит? При выполнении сложения для массива запускается метод toString? Разве метод toString не должен запускаться только при попытке преобразования объекта к строке (String, alert...)? А в этом случае я не пытаюсь преобразовать массив к строке...
Ответы (1 шт):
Согласно Флэнагану (JavaScript. Полное руководство, 7-е издание - 2021):
Операция + в JavaScript выполняет сложение чисел и конкатенацию строк. Если любой из ее операндов оказывается объектом, то интерпретатор JavaScript преобразует его в элементарное значение с применением алгоритма no-preference. После получения двух элементарных значений проверяются их типы. Если один из аргументов является строкой, тогда другой преобразовывается в строку и выполняется конкатенация строк.
То есть, массив преобразуется в строку, почему:
Алгоритм no-preference зависит от класса преобразуемого объекта. Если объект относится к классу Date, тогда интерпретатор JavaScript применяет алгоритм prefer-string. Для любого другого объекта интерпретатор JavaScript использует агоритм prefer-number.
Алгоритм prefer-number первым испытывает valueOf(), а вторым - toString().
(Если valueOf() не существует или возвращает объект). Другими словами, массив должен бы преобразоваться в число, НО:
Класс Array наследует стандартный метод valueOf(), который не возвращает элементарное значение. Таким образом, когда мы пытаемся преобразовать массив в число, то в итоге получаем вызов метода toString() массива.
Массив с единственным элементом преобразуется в ту же строку, что и этот один элемент. Если массив содержит единственное число, то оно преобразуется в строку.
Таким образом, массив, в силу того, что его метод valueOf() возвращает сам массив как объект, в итоге возвращает результат вызова toString().
Для эксперимента можно переписать метод valueOf():
Array.prototype.valueOf = function(){
return Number(this[0]);
}
console.log([5] + 25);
То, что возвращает родной valueOf() для сравнения:
console.log([5].valueOf());