В 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 () явно в контекстах, которые подразумевали строку.
Это - просто способ, которым это?
Причина, по которой ("x =" + x) дает "x = значение", а не "x = tostring", заключается в следующем. При оценке «+» javascript сначала собирает примитивные значения операндов, а затем решает, следует ли применять сложение или конкатенацию, в зависимости от типа каждого примитива.
Итак, как вы думаете, это работает
a + b:
pa = ToPrimitive(a)
if(pa is string)
return concat(pa, ToString(b))
else
return add(pa, ToNumber(b))
, и это то, что на самом деле происходит
a + b:
pa = ToPrimitive(a)
pb = ToPrimitive(b)*
if(pa is string || pb is string)
return concat(ToString(pa), ToString(pb))
else
return add(ToNumber(pa), ToNumber(pb))
То есть toString применяется к результату valueOf, а не к вашему исходному объекту.
Дополнительную информацию см. В разделе 11.6.1 Оператор сложения (+) в спецификации языка ECMAScript.
* При вызове в строковом контексте ToPrimitive вызывает toString, но здесь дело обстоит не так, потому что '+' не применяет какой-либо контекст типа.
Вот еще немного подробностей, прежде чем я перейду к ответу:
var x = {
toString: function () { return "foo"; },
valueOf: function () { return 42; }
};
alert(x); // foo
"x=" + x; // "x=42"
x + "=x"; // "42=x"
x + "1"; // 421
x + 1; // 43
["x=", x].join(""); // "x=foo"
Функция toString
- это , а не ] "превзойден" по valueOf
в целом. Стандарт ECMAScript действительно хорошо отвечает на этот вопрос. Каждый объект имеет свойство [[DefaultValue]]
, которое вычисляется по запросу. При запросе этого свойства интерпретатор также дает «подсказку» о том, какое значение он ожидает. Если подсказка String
, тогда toString
используется перед valueOf
. Но если подсказка - Number
, тогда сначала будет использоваться valueOf
. Обратите внимание, что если присутствует только один или он возвращает не примитив, он обычно вызывает другой как второй вариант.
Оператор +
всегда предоставляет подсказку Число
, даже если первый операнд является строковым значением. Несмотря на то, что он запрашивает у x
свое представление Number
, поскольку первый операнд возвращает строку из [[DefaultValue]]
, он выполняет конкатенацию строк.
Если вы хотите гарантировать, что toString
вызывается для конкатенации строк, используйте массив и метод .join ("")
.
(Однако ActionScript 3.0 немного изменяет поведение +
.Если любой из операндов является строкой
, он будет рассматривать ее как оператор конкатенации строк и использовать подсказку String
при вызове [[DefaultValue]]
. Итак, в AS3 этот пример дает «foo, x = foo, foo = x, foo1, 43, x = foo».)