Щоб доповнити відповідь Уейна і спробувати пояснити, чому ToPrimitive([])
повертається ""
, варто розглянути два можливі типи відповідей на питання "чому". Перший тип відповіді: "оскільки специфікація говорить, що так поводитиметься JavaScript". У специфікації ES5, розділ 9.1 , де описано результат ToPrimitive як значення за замовчуванням для Об'єкта:
Значення об'єкта за замовчуванням отримується за допомогою виклику внутрішнього методу [[DefaultValue]], передаючи необов'язковий підказку PreferredType.
Розділ 8.12.8 описує [[DefaultValue]]
метод. Цей метод приймає "підказку" як аргумент, а підказка може бути як String, так і Number. Щоб спростити справу, розпочавшись з деякими деталями, якщо натяк є String, то [[DefaultValue]]
повертає значення, toString()
якщо воно існує, і повертає примітивне значення, а в іншому випадку повертає значення valueOf()
. Якщо натяк - Число, пріоритети toString()
і valueOf()
змінюються таким чином, що valueOf()
називається першим, а його значення повертається, якщо це примітив. Таким чином, [[DefaultValue]]
повертає результат toString()
чиvalueOf()
залежить від зазначеного PreferredType для об'єкта та повертають чи ні ці функції примітивні значення.
Метод valueOf()
Object за замовчуванням просто повертає сам об’єкт, що означає, що якщо клас не перекриє метод за замовчуванням, він valueOf()
просто повертає сам Object. Це справа для Array
. [].valueOf()
повертає сам об’єкт []
. Оскільки Array
об’єкт не є примітивом, [[DefaultValue]]
підказка не має значення: значенням повернення для масиву буде значенняtoString()
.
Процитуючи JavaScript Девіда Фланагана : Посібник з визначенням , який, до речі, є чудовою книгою, яка повинна стати першим місцем для отримання відповідей на такі типи питань:
Деталі цього перетворення об'єкта в число пояснюють, чому порожній масив перетворюється на число 0 і чому масив з одним елементом також може перетворюватися на число. Масиви успадковують метод valueOf () за замовчуванням, який повертає об'єкт, а не примітивне значення, тому перетворення масиву в число покладається на метод toString (). Порожні масиви перетворюються на порожній рядок. І порожній рядок перетворюється на число 0. Масив з одним елементом перетворюється на той самий рядок, що і один елемент. Якщо масив містить одне число, це число перетворюється в рядок, а потім повертається до числа.
Другий тип відповіді на питання "чому", окрім "тому, що говорить специфікація", дає певне пояснення, чому поведінка має сенс з дизайнерської точки зору. З цього питання можу лише міркувати. По-перше, як можна перетворити масив у число? Єдиною розумною можливістю, яку я думаю, було б перетворення порожнього масиву в 0, а будь-який не порожній масив до 1. Але, як показала відповідь Вейна, порожній масив все одно буде перетворений на 0 для багатьох типів порівнянь. Крім цього, важко придумати розумне примітивне повернене значення для Array.valueOf (). Отже, можна стверджувати, що це просто більше сенсу мати Array.valueOf()
дефолт і повертати сам масив, що веде за собоюtoString()
до результату, використовуваного ToPrimitive. Просто має сенс перетворювати масив у рядок, а не в число.
Більше того, як натякає цитата Фланагана, це дизайнерське рішення дійсно дає змогу використовувати певні типи корисної поведінки. Наприклад:
var a = [17], b = 17, c=1;
console.log(a==b); // <= true
console.log(a==c); // <= false
Така поведінка дозволяє порівняти одноелементний масив з числами та отримати очікуваний результат.