valueOf () против toString () в JavaScript - PullRequest
109 голосов
/ 21 марта 2010

В 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 () давала мне его величину, но всякий раз, когда я хотел преобразовать в строку, яхотел бы что-то вроде "+ би".И я бы не хотел вызывать toString () явно в контекстах, которые подразумевали строку.

Это так, как есть?

Ответы [ 2 ]

101 голосов
/ 21 марта 2010

Причина, по которой ("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, но здесь это не так, поскольку '+' не применяет никакого контекста типа.

72 голосов
/ 21 марта 2010

Вот немного подробнее, прежде чем я доберусь до ответа:

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».)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...