Вот немного подробнее, прежде чем я доберусь до ответа:
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
. Обратите внимание, что если присутствует только один из них или он возвращает не примитив, он обычно вызывает другой вариант как второй.
Оператор +
всегда предоставляет подсказку Number
, даже если первый операнд является строковым значением. Хотя он запрашивает x
для представления Number
, поскольку первый операнд возвращает строку из [[DefaultValue]]
, он выполняет конкатенацию строк.
Если вы хотите гарантировать, что toString
вызывается для конкатенации строк, используйте массив и метод .join("")
.
(однако ActionScript 3.0 немного изменяет поведение +
. Если любой из операндов является String
, он будет обрабатывать его как оператор конкатенации строк и использовать подсказку String
при вызове [[DefaultValue]]
. Итак, в AS3 этот пример выдает «foo, x = foo, foo = x, foo1, 43, x = foo».)