Qual é a diferença entre String (value) vs value.toString ()

105

Javascript tem muitos "truques" em torno de tipos e conversões de tipo, então estou me perguntando se esses 2 métodos são os mesmos ou se há algum caso que os torna diferentes?

AlfaTeK
fonte

Respostas:

123

Eles não são completamente iguais e, na verdade, o construtor String chamado como uma função (seu primeiro exemplo) irá, no final, chamar o toStringmétodo do objeto passado, por exemplo:

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

Por outro lado, se um identificador se referir a nullou undefined, você não puder usar o toStringmétodo, ele apresentará uma TypeErrorexceção :

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

O Stringconstrutor chamado como uma função seria aproximadamente equivalente a:

value + '';

As regras de conversão de tipo de Objeto- para- Primitivo são descritas detalhadamente na especificação, a [[DefaultValue]]operação interna.

Resumindo resumidamente, ao converter de objeto- para- string , as seguintes etapas são executadas:

  1. Se disponível, execute o toStringmétodo.
    • Se resultfor um primitivo , retorne result, caso contrário, vá para a Etapa 2.
  2. Se disponível, execute o valueOfmétodo.
    • Se resultfor um primitivo , retorne result, caso contrário, vá para a Etapa 3.
  3. Jogue TypeError.

Dadas as regras acima, podemos dar um exemplo da semântica envolvida:

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
}

Se você quiser saber mais sobre este mecanismo, eu recomendo olhar para ToPrimitivee as ToStringoperações internas.

Também recomendo a leitura deste artigo:

CMS
fonte
1
Existe uma terceira "maneira", se você chamar isso: new String(value)em qualquer valor, ele sempre retornará um objeto string.
Herbertusz
@Herbertusz new String({toString: null})joga a TypeError.
Константин Ван
Com a adição de símbolos String()e + ''agora temos uma diferença bastante significativa. String(Symbol())irá executar, mas Symbol() + ''irá lançar um erro (e Symbol () irá passar por um guarda falsey, ao contrário de null e undefined, então x && (x + '')agora pode lançar).
yeerk
24

value.toString()causará um erro se valuefor nulo. String(value)não deveria.

Por exemplo:

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

vai falhar porque value == null.

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

deve exibir uma mensagem "null" (ou semelhante), mas não travará.

Jonathan
fonte
3
Eu nunca vi uma exceção de ponteiro nulo em javascript ... onde você viu isso?
Dagg Nabbit de
legais. seria ainda melhor com um exemplo
mykhal
@não, @casablanca corrigido. Estou acostumado com Java. @mykhal Como isso se parece?
Jonathan,
Ele retorna uma string "null" :)
moefinley
1

String(value)deve ter o mesmo resultado que value.toString()em todos os casos, exceto para valores sem propriedades como nullou undefined. ''+valueproduzirá o mesmo resultado.

Dagg Nabbit
fonte
1

String () [a chamada do construtor ] está basicamente chamando o .toString ()

.toString () e String () podem ser chamados em valores primitivos (número, booleano, string) e basicamente não farão nada de especial:

verdadeiro => 'verdadeiro'

falso => ​​'falso'

17 => '17'

'olá' => 'olá'

Mas chamar essas funções em objetos é onde as coisas ficam interessantes:

se o objeto tiver sua própria função .toString (), ele será chamado sempre que você precisar que este objeto seja tratado como uma string (explicitamente / implicitamente)

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

A propósito, se você quiser tratar este objeto como um número, ele deve ter uma função .valueOf () definida nele.

e se tivermos ambos em um objeto?

se quisermos tratar este objeto como uma string => use .toString ()

se quisermos tratar este objeto como um número => use .valueOf ()

e se tivermos apenas .valueOf () definido?

.valueOf () definido dentro do objeto será chamado se queremos tratar o objeto como uma string ou como um número

Louay Alosh
fonte