В чем разница между String (значение) и value.toString ()

108

В Javascript есть много "хитростей" вокруг типов и преобразований типов, поэтому мне интересно, одинаковы ли эти 2 метода или есть какой-то угловой случай, который их отличает?

АльфаТек
источник

Ответы:

126

Они не полностью одинаковы, и на самом деле конструктор String, вызываемый как функция (ваш первый пример), в конце вызовет toStringметод переданного объекта, например:

var o = { toString: function () { return "foo"; } };
String(o); // "foo"

С другой стороны, если идентификатор ссылается на nullили undefined, вы не можете использовать toStringметод, он выдаст вам TypeErrorисключение :

var value = null;
String(null);     // "null"
value.toString(); // TypeError

StringКонструктор вызывается как функция будет примерно эквивалентно:

value + '';

Правила преобразования типа от объекта -До- Примитивными подробно описано описаны на спецификации, на [[DefaultValue]]внутренней операции.

Кратко, при преобразовании из Объекта -До- строки , выполняются следующие шаги:

  1. Если возможно, выполните toStringметод.
    • Если resultэто примитив , вернитесь result, в противном случае перейдите к шагу 2.
  2. Если возможно, выполните valueOfметод.
    • Если resultявляется примитивом , вернитесь result, в противном случае перейдите к шагу 3.
  3. Брось TypeError.

Учитывая приведенные выше правила, мы можем сделать пример задействованной семантики:

var o = {
  toString: function () { return "foo"; },
  valueOf:  function () { return "bar"; }
};

String(o); // "foo"

// Make the toString method unavailable:
o.toString = null;

String(o); // "bar"

// Also make the valueOf method unavailable:
o.valueOf = null;

try { 
  String(o); 
} catch (e) {
  alert(e); // TypeError
}

Если вы хотите узнать больше об этом механизме, я бы порекомендовал взглянуть на ToPrimitiveи ToStringвнутренние операции.

Также рекомендую прочитать эту статью:

Кристиан К. Сальвадо
источник
1
Есть третий «способ», если вы его назовете: new String(value)при любом значении он всегда будет возвращать строковый объект.
Herbertusz
@Herbertusz new String({toString: null})бросает TypeError.
Константин Ван
С добавлением символов String()и + ''теперь есть довольно существенная разница. String(Symbol())будет работать, но Symbol() + ''выдаст ошибку (и Symbol () передаст ложную охрану, в отличие от null и undefined, поэтому x && (x + '')теперь может вызывать ).
yeerk 06
24

value.toString()вызовет ошибку, если valueимеет значение null. String(value)не должна.

Например:

var value = null;
alert(value.toString());

потерпит неудачу, потому что value == null.

var value = null;
alert(String(value));

должен отображать сообщение, читающее "null" (или подобное), но не произойдет сбой.

Джонатан
источник
3
Я никогда не видел исключения нулевого указателя в javascript ... где вы это видели?
Дагг Наббит
отлично. еще лучше было бы на примере
михал
@no, @casablanca Исправлено. Я привык к Java. @mykhal Как это выглядит?
Джонатан
Возвращает строку "null" :)
moefinley
1

String(value)должен иметь тот же результат, что и value.toString()в любом случае, за исключением значений без таких свойств, как nullили undefined. ''+valueдаст тот же результат.

Дагг Наббит
источник
1

String () [ вызов конструктора ] в основном вызывает .toString ()

.toString () и String () могут вызываться для примитивных значений (число, логическое значение, строка) и в основном ничего особенного делать не будут:

истина => 'правда'

false => 'ложь'

17 => '17'

'привет' => 'привет'

Но при вызове этих функций для объектов все становится интересно:

если у объекта есть собственная функция .toString (), она будет вызываться, когда вам понадобится, чтобы этот объект обрабатывался как строка (явно / неявно)

let obj = {
           myName:"some object",
           toString:function(){ return this.myName; } 
          }

//implicitly treating this obj as a string
"hello " + obj; //"hello some object"

//OR (explicitly)
"hello " + String(obj) //calling the existent toString function

//OR
"hello " + obj.toString(); //calling toString directly

Кстати, если вы хотите рассматривать этот объект как число, в нем должна быть определена функция .valueOf () .

что, если у нас есть и то, и другое в одном объекте?

если мы хотим рассматривать этот объект как строку => используйте .toString ()

если мы хотим рассматривать этот объект как число => используйте .valueOf ()

что, если у нас есть только .valueOf () ?

.valueOf (), определенный внутри объекта, будет вызываться независимо от того, хотим ли мы обработать объект как строку или как число.

Луай Алош
источник