Чтобы дополнить ответ Уэйна и попытаться объяснить, почему ToPrimitive([])
возвращается ""
, стоит рассмотреть два возможных типа ответов на вопрос «почему». Первый тип ответа: «потому что в спецификации сказано, что именно так будет вести себя JavaScript». В спецификации ES5, раздел 9.1 , который описывает результат ToPrimitive в качестве значения по умолчанию для объекта:
Значение объекта по умолчанию извлекается путем вызова внутреннего метода [[DefaultValue]] объекта, передавая необязательную подсказку PreferredType.
Раздел 8.12.8 описывает [[DefaultValue]]
метод. Этот метод принимает «подсказку» в качестве аргумента, и подсказка может быть либо String, либо Number. Чтобы упростить этот вопрос, отказавшись от некоторых деталей, если подсказкой является строка, то [[DefaultValue]]
возвращается значение, toString()
если оно существует, и возвращается примитивное значение, а в противном случае возвращается значение valueOf()
. Если подсказка является Number, приоритеты toString()
и valueOf()
меняются местами, так что valueOf()
сначала вызывается и возвращается его значение, если это примитив. Таким образом, [[DefaultValue]]
возвращает ли результат результат toString()
или valueOf()
зависит от указанного PreferredType для объекта и возвращают ли эти функции примитивные значения.
Метод valueOf()
Object по умолчанию просто возвращает сам объект, а это означает, что если класс не переопределяет метод по умолчанию, он valueOf()
просто возвращает сам объект. Это дело для 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
Такое поведение позволяет сравнивать одноэлементный массив с числами и получать ожидаемый результат.