Обычно объекты преобразуются в значения элементарных типов достаточно прямолинейным способом, о котором рассказывалось в разделе 3.5.3. Однако на вопросах преобразования объектов следует остановиться более подробно.1
Прежде всего следует заметить, что попытка преобразования непустых объектов
в логическое значение дает в результате значение true. Это справедливо для лю_ бых объектов (включая массивы и функции), даже для объектов_оберток, кото_ рые представляют элементарные типы, при другом способе преобразования даю_ щие значение false. Например, все нижеследующие объекты преобразуются
в значение true при использовании их в логическом контексте:
new Boolean(false) // Внутреннее значение – false, но объект преобразуется в true new Number(0)
new String("") new Array( )
В табл. 3.3 описывается порядок преобразования объектов в числовые значения, когда сначала вызывается метод объекта valueOf(). Большинство объектов по умолчанию наследуют метод valueOf() от базового объекта Object, который воз_ вращает сам объект. Поскольку по умолчанию метод valueOf() не возвращает значение элементарного типа, далее интерпретатор JavaScript пытается преоб_ разовать объект в число вызовом метода toString() с последующим преобразова_ нием строки в число.
В случае массивов это приводит к весьма интересным результатам. Метод toString() у массивов преобразует элементы массива в строки и возвращает ре_ зультат операции конкатенации этих строк, разделяя отдельные элементы мас_ сива запятыми. Таким образом, пустой массив преобразуется в пустую строку, что в результате дает число 0! Кроме того, если массив состоит из единственного элемента, содержащего число n, весь массив преобразуется в строковое представ_ ление числа n, которое затем будет вновь преобразовано в число n. Если массив содержит более одного элемента или единственный элемент массива не является числом, результатом преобразования будет значение NaN.
Тип преобразования зависит от контекста, в котором это преобразование произ_ водится. Существуют такие ситуации, когда невозможно однозначно определить контекст. Оператор + и операторы сравнения (<, <=, > и >=) могут оперировать как числами, так и строками, таким образом, когда в одной из таких операций уча_ ствует объект, возникает неоднозначность: в значение какого типа следует пре_ образовать объект – в строку или в число. В большинстве случаев интерпретатор JavaScript сначала пытается преобразовать объект с помощью метода valueOf(). Если этот метод возвращает значение элементарного типа (как правило, число), тогда используется это значение. Однако чаще всего метод valueOf() возвращает непреобразованный объект, и тогда интерпретатор JavaScript пытается преобра_ зовать объект в строку вызовом метода toString().
1 Этот раздел содержит достаточно сложный материал, который при первом про_ чтении можно пропустить.
3.15. По значению или по ссылке
Однако здесь есть одно исключение из правил: когда с оператором + использует_ ся объект Date, преобразование сразу начинается с вызова метода toString(). Это исключение обусловлено тем обстоятельством, что объект Date обладает собст_ венными реализациями методов toString() и valueOf(). Однако когда объект Date указывается с оператором +, чаще всего подразумевается операция конкатена_ ции строк, а при выполнении операции сравнения практически всегда требуется определить, какая из двух дат является более ранней по времени.
Большинство объектов либо вообще не имеют метода valueOf(), либо этот метод не возвращает значение требуемого элементарного типа. Когда объект использу_ ется с оператором +, обычно выполняется операция конкатенации строк вместо сложения чисел. Аналогично, когда объект участвует в операциях сравнения, обычно производится сравнение строковых значений, а не чисел.
Объекты, обладающие собственной реализацией метода valueOf(), могут вести себя иначе. Если вы переопределите метод valueOf(), чтобы он возвращал число, над объектом можно будет выполнять арифметические и другие числовые опера_ ции, но операция сложения объекта со строкой может не дать желаемого резуль_ тата, поскольку метод valueOf() возвратит значение элементарного типа, и метод toString() вызван уже не будет. В результате к строке будет добавляться строко_ вое представление числа, возвращаемого методом valueOf().
Наконец, следует запомнить, что метод valueOf() не вызывает метод toNumber(). Строго говоря, назначение этого метода состоит в том, чтобы преобразовать объ_ ект в разумное значение элементарного типа; по этой причине в некоторых объ_ ектах методы valueOf() возвращают строку.