В чем разница между valueOf и toString

Artem Palamarchuk

В чем разница между ними? И то, и то выводит нам строку, которую мы указывает в return, при том valueOf, если явно указано, затирает toString. Почитал пару источников, но так и не понял разницы. Если можно, поподробнее, пожалуйста.

2 ответа

Artem Palamarchuk

Рискну предположить что Вы имеете ввиду функции valueOf и toString. Разница между ними чуть размыта, но понятна:

  • valueOf используется для численного преобразования объекта (foo + 42, ++bar, etc.). Но есть он далеко не у всех объектов (т. е. есть, но возвращает сам объект, поэтому игнорируется) и обязан возвращать примитив, иначе будет проигнорирован и будет вызван toString.
  • toString используется для строкового преобразования объекта (alert(foo)). Есть у всех объектов, обычно не очень информативен ([object Object]), но очень удобен, если нужно перегрузить оператор, например (в JS нет перегрузки/создания операторов). Тоже обязан вернуть примитив.

Читать подробнее. У использования этих операторов есть нюансы (как везде в JS, наверное, экой коварный язык однако!), которые проще узнать из спецификации.


Artem Palamarchuk

Если непонятно в источниках, стоит обратиться к спецификации: какой из данных методах будет вызван определяется внутри абстрактной операции ToPrimitive, которая выполняется практически при всех операциях с объектами, например: арифметические операции, операции сравнения и т.д.

Операция ToPrimitive ( input [, PreferredType] )

Когда Type(input) - Object, выполняются следующие шаги:

  1. Если PreferredType отсутствует, hint будет "default".
  2. Если PreferredType подсказывает String, hint будет "string".
  3. Если PreferredType подсказывает Number, hint будет "number".
  4. Пусть exoticToPrim - GetMethod(input, @@toPrimitive).
  5. Если exoticToPrim это не undefined, тогда

    1. result будет Call(exoticToPrim, input, «hint»). ReturnIfAbrupt(result).
    2. Если Type(result) не Object, вернуть result.
    3. Бросить исключение TypeError.
  6. Если hint="default", hint будет "number".

  7. Вернуть результат OrdinaryToPrimitive(input,hint).

Как видно из алгоритма, если у объекта нет внутренней экзотической функции для приведения к примитивному значению будет вызываться OrdinaryToPrimitive.

При вызове абстрактной операции OrdinaryToPrimitive с аргументами O и hint, будут выполняться следующие шаги:

  1. Проверка типа: Type(O) - Object
  2. Проверка типа: Type(hint) это String и значение "string" или "number".
  3. Если hint = "string", тогда
    1. methodNames будет списком «"toString", "valueOf"».
  4. Иначе,
    1. methodNames будет списком «"valueOf", "toString"».
  5. Для каждого name из methodNames
    1. method будет Get(O, name).
    2. Если IsCallable(method) = true, тогда
    3. result = Call(method, O).
    4. Если Type(result) не Object, вернуть result.
  6. Бросить исключение TypeError.

Примечание: Когда ToPrimitive вызывается без параметра hint, поведение такое же, как в случае передачи hint значения Number. Однако, объекты могут переопределить это поведения определив метод @@toPrimitive. Из объектов в текущей спецификации только объекты Date и Symbol переопределяют поведение по умолчанию. Объекты Date рассматривает вызов без передачи hint, как будто передали String.

licensed under cc by-sa 3.0 with attribution.