В Javascript каждый объект имеет методы valueOf () и toString (). Я бы подумал, что метод toString () вызывается всякий раз, когда вызывается преобразование строки, но, очевидно, он превосходит valueOf ().
Например, код
var x = {toString: function() {return "foo"; },
valueOf: function() {return 42; }};
window.console.log ("x="+x);
window.console.log ("x="+x.toString());
напечатает
x=42
x=foo
Это кажется мне обратным ... например, если бы x было комплексным числом, я бы хотел, чтобы valueOf () давал мне его величину, но всякий раз, когда я хотел преобразовать в строку, я хотел бы что-то вроде «a + bi». И я бы не хотел вызывать toString () явно в контекстах, подразумевающих строку.
Это просто так?
javascript
brainjam
источник
источник
window.console.log (x);
илиalert (x);
?alert(x)
отображаетсяfoo
иwindow.console.log(x)
отображаетсяObject { toString: x.toString(), valueOf: x.valueOf() }
.Ответы:
Причина, по которой ("x =" + x) дает "x = значение", а не "x = tostring", заключается в следующем. При оценке «+» javascript сначала собирает примитивные значения операндов, а затем решает, следует ли применять сложение или конкатенацию, в зависимости от типа каждого примитива.
Итак, как вы думаете, это работает
и вот что происходит на самом деле
То есть toString применяется к результату valueOf, а не к вашему исходному объекту.
Дополнительные сведения см. В разделе 11.6.1 Оператор сложения (+) в спецификации языка ECMAScript.
* При вызове в контексте строки, ToPrimitive делает Invoke ToString, но это не тот случай, потому что «+» не навязывает какой - либо контекст типа.
источник
Прежде чем я перейду к ответу, расскажу немного подробнее:
toString
Функция не «переиграла» наvalueOf
в целом. Стандарт ECMAScript действительно хорошо отвечает на этот вопрос. У каждого объекта есть[[DefaultValue]]
свойство, которое вычисляется по запросу. При запросе этого свойства интерпретатор также дает «подсказку» о том, какое значение он ожидает. Если подсказка естьString
, тоtoString
используется раньшеvalueOf
. Но, если подсказка естьNumber
, тоvalueOf
сначала будет использовано. Обратите внимание, что если присутствует только один или он возвращает не примитив, он обычно вызывает другой как второй вариант.+
Оператор всегда дает подсказкуNumber
, даже если первый операнд является строкой. Несмотря на то, что он запрашиваетx
егоNumber
представление, поскольку первый операнд возвращает строку из[[DefaultValue]]
, он выполняет конкатенацию строк.Если вы хотите гарантировать, что
toString
вызывается конкатенация строк, используйте массив и.join("")
метод.(ActionScript 3.0
+
, однако, немного изменяет поведение . Если любой из операндов является aString
, он будет рассматривать его как оператор конкатенации строк и использовать подсказкуString
при вызове[[DefaultValue]]
. Таким образом, в AS3 этот пример дает "foo, x = foo, foo = x, foo1, 43, x = foo ".)источник
valueOf
ortoString
возвращает непримитивы, они игнорируются. Если ни один из них не существует или ни один из них не возвращает примитив, то создается aTypeError
.[[DefaultValue]](no-hint)
, что эквивалентно[[DefaultValue]](number)
.("" + new Date(0)) === new Date(0).toString()
, Кажется, что объект Date всегда возвращает своеtoString()
значение, когда он к чему-то добавляется.TLDR
Приведение типов, или неявное преобразование типов, обеспечивает слабую типизацию и используется во всем JavaScript. Большинство операторов (за заметным исключением операторов строгого равенства
===
и!==
) и операций проверки значений (например,if(value)...
) будут приводить значения, предоставленные им, если типы этих значений не сразу совместимы с операцией.Точный механизм, используемый для приведения значения, зависит от оцениваемого выражения. В вопросе используется оператор сложения .
Оператор сложения сначала гарантирует, что оба операнда являются примитивами, что в данном случае включает вызов
valueOf
метода. ВtoString
этом экземпляре метод не вызывается, так как переопределенныйvalueOf
метод объектаx
возвращает примитивное значение.Затем, поскольку один из операндов в вопросе является строкой, оба операнда преобразуются в строки. Этот процесс использует абстрактную внутреннюю операцию
ToString
(примечание: с заглавной буквы) и отличается отtoString
метода объекта (или его цепочки прототипов).Наконец, результирующие строки объединяются.
подробности
В прототипе каждого объекта функции конструктора, соответствующего каждому типу языка в JavaScript (например, Number, BigInt, String, Boolean, Symbol и Object), есть два метода:
valueOf
иtoString
.Цель
valueOf
- получить примитивное значение, связанное с объектом (если он есть). Если объект не имеет базового примитивного значения, то объект просто возвращается.Если
valueOf
вызывается для примитива, то примитив автоматически упаковывается в коробку обычным способом, и возвращается базовое значение примитива. Обратите внимание, что для строк базовое примитивное значение (т. Е. Значение, возвращаемоеvalueOf
) является самим строковым представлением.Следующий код показывает, что
valueOf
метод возвращает базовое примитивное значение из объекта-оболочки, и показывает, как неизмененные экземпляры объекта, которые не соответствуют примитивам, не имеют примитивного значения для возврата, поэтому они просто возвращают себя.С
toString
другой стороны, цель - вернуть строковое представление объекта.Например:
Для большинства операций JavaScript будет молча попытаться преобразовать один или несколько операндов в требуемый тип. Это поведение было выбрано, чтобы упростить использование JavaScript. Изначально в JavaScript не было исключений , и это тоже могло сыграть роль в этом дизайнерском решении. Такой вид неявного преобразования типов называется приведением типов и является основой свободной (слабой) системы типов JavaScript. Сложные правила, лежащие в основе такого поведения, призваны перенести сложность приведения типов в сам язык и из вашего кода.
В процессе принуждения могут происходить два режима преобразования:
Number()
,Boolean()
, ИString()
т.д.)Преобразование в примитив
При попытке преобразовать непримитивные типы в примитивы, над которыми нужно работать, абстрактная операция
ToPrimitive
вызывается с необязательной «подсказкой» типа «число» или «строка». Если подсказка опущена, подсказка по умолчанию - «число» (если@@toPrimitive
метод не был переопределен). Если подсказка - строка, тоtoString
сначала выполняется попытка, а затем ,valueOf
еслиtoString
примитив не вернул. Иначе наоборот. Подсказка зависит от операции, запрашивающей преобразование.Оператор сложения не подсказывает, поэтому
valueOf
сначала выполняется попытка. Оператор вычитания дает намек на «число», поэтомуvalueOf
сначала выполняется попытка. Единственные ситуации, которые я могу найти в спецификации, в которых подсказка является «строкой»:Object#toString
ToPropertyKey
, которая преобразует аргумент в значение, которое может использоваться как ключ свойства.Прямое преобразование типа
У каждого оператора есть свои правила выполнения своей операции. Сначала будет использоваться оператор сложения,
ToPrimitive
чтобы убедиться, что каждый операнд является примитивом; затем, если один из операндов является строкой, он намеренно вызывает абстрактную операциюToString
для каждого операнда, чтобы обеспечить поведение конкатенации строк, которое мы ожидаем со строками. Если послеToPrimitive
шага оба операнда не являются строками, выполняется арифметическое сложение.В отличие от сложения, оператор вычитания не имеет перегруженного поведения, поэтому он будет вызываться
toNumeric
для каждого операнда, предварительно преобразовав их в примитивы с помощьюToPrimitive
.Так:
Обратите внимание, что
Date
внутренний объект уникален в том смысле, что это единственное внутреннее свойство, которое переопределяет@@toPrimitive
метод по умолчанию , в котором подсказка по умолчанию считается «строкой» (а не «числом»). Причина в томDate
, что для удобства программиста экземпляры по умолчанию переводятся в читаемые строки, а не в их числовые значения. Вы можете переопределить@@toPrimitive
свои собственные объекты, используяSymbol.toPrimitive
.В следующей таблице показаны результаты принуждения для абстрактного оператора равенства (
==
) ( источник ):См. Также .
источник