Em Javascript, todo objeto tem um método valueOf () e toString (). Eu teria pensado que o método toString () fosse invocado sempre que uma conversão de string fosse solicitada, mas aparentemente ele é superado por valueOf ().
Por exemplo, o código
var x = {toString: function() {return "foo"; },
valueOf: function() {return 42; }};
window.console.log ("x="+x);
window.console.log ("x="+x.toString());
irá imprimir
x=42
x=foo
Isso me parece estar ao contrário .. se x fosse um número complexo, por exemplo, eu gostaria que valueOf () me desse sua magnitude, mas sempre que eu quisesse converter para uma string, eu gostaria de algo como "a + bi". E eu não gostaria de ter que chamar toString () explicitamente em contextos que impliquem uma string.
É assim que as coisas são?
javascript
cérebro
fonte
fonte
window.console.log (x);
oualert (x);
?alert(x)
exibidofoo
ewindow.console.log(x)
exibidoObject { toString: x.toString(), valueOf: x.valueOf() }
.Respostas:
A razão pela qual ("x =" + x) dá "x = valor" e não "x = tostring" é a seguinte. Ao avaliar "+", o javascript primeiro coleta os valores primitivos dos operandos e, em seguida, decide se a adição ou concatenação deve ser aplicada, com base no tipo de cada primitiva.
Então, é assim que você acha que funciona
e isso é o que realmente acontece
Ou seja, toString é aplicado ao resultado de valueOf, não ao seu objeto original.
Para obter mais referências, consulte a seção 11.6.1 O operador Addition (+) na Especificação de linguagem ECMAScript.
* Quando chamado em um contexto string, ToPrimitive faz invocar toString, mas este não é o caso aqui, porque '+' não impõe qualquer contexto tipo.
fonte
Aqui estão mais alguns detalhes, antes de eu chegar à resposta:
A
toString
função não é "superada" pelovalueOf
geral. O padrão ECMAScript responde muito bem a essa pergunta. Cada objeto possui uma[[DefaultValue]]
propriedade, que é calculada sob demanda. Ao solicitar essa propriedade, o interpretador também fornece uma "dica" do tipo de valor que ele espera. Se a dica forString
, entãotoString
será usado antesvalueOf
. Mas, se a dica forNumber
, entãovalueOf
será usada primeiro. Observe que se apenas um estiver presente ou se ele retornar um não primitivo, ele geralmente chamará o outro como a segunda escolha.O
+
operador sempre fornece a dicaNumber
, mesmo se o primeiro operando for um valor de string. Mesmo que peçax
suaNumber
representação, como o primeiro operando retorna uma string de[[DefaultValue]]
, ele faz a concatenação de strings.Se você quiser garantir que
toString
seja chamado para concatenação de string, use uma matriz e o.join("")
método.(O ActionScript 3.0 modifica ligeiramente o comportamento de
+
, no entanto. Se um dos operandos for aString
, ele o tratará como um operador de concatenação de string e usará a dicaString
ao chamar[[DefaultValue]]
. Portanto, no AS3, este exemplo produz "foo, x = foo, foo = x, foo1, 43, x = foo ".)fonte
valueOf
outoString
retornar não-primitivos, eles serão ignorados. Se nenhum deles existir ou se nenhum retornar um primitivo, aTypeError
será lançado.[[DefaultValue]](no-hint)
, que é equivalente a[[DefaultValue]](number)
.("" + new Date(0)) === new Date(0).toString()
. Um objeto Date sempre parece retornar seutoString()
valor quando é adicionado a algo.TLDR
A coerção de tipo, ou conversão de tipo implícita, permite a digitação fraca e é usada em todo o JavaScript. A maioria dos operadores (com a notável exceção dos operadores de igualdade estrita
===
e!==
) e operações de verificação de valor (por exemploif(value)...
), forçará os valores fornecidos a eles, se os tipos desses valores não forem imediatamente compatíveis com a operação.O mecanismo preciso usado para coagir um valor depende da expressão que está sendo avaliada. Na pergunta, o operador de adição está sendo usado.
O operador de adição primeiro garantirá que ambos os operandos sejam primitivos, o que, neste caso, envolve a chamada do
valueOf
método. OtoString
método não é chamado nesta instância porque ovalueOf
método sobrescrito no objetox
retorna um valor primitivo.Então, como um dos operandos em questão é uma string, ambos os operandos são convertidos em strings. Esse processo usa a operação interna abstrata
ToString
(nota: letras maiúsculas) e é diferente dotoString
método no objeto (ou de sua cadeia de protótipo).Finalmente, as strings resultantes são concatenadas.
Detalhes
No protótipo de cada objeto de função do construtor correspondente a cada tipo de linguagem em JavaScript (ou seja, Number, BigInt, String, Boolean, Symbol e Object), existem dois métodos:
valueOf
etoString
.O objetivo de
valueOf
é recuperar o valor primitivo associado a um objeto (se houver). Se um objeto não tiver um valor primitivo subjacente, o objeto será simplesmente retornado.Se
valueOf
for invocado contra um primitivo, então o primitivo é automaticamente encaixotado da maneira normal e o valor primitivo subjacente é retornado. Observe que, para strings, o valor primitivo subjacente (ou seja, o valor retornado porvalueOf
) é a própria representação da string.O código a seguir mostra que o
valueOf
método retorna o valor primitivo subjacente de um objeto wrapper e mostra como as instâncias de objeto não modificadas que não correspondem aos primitivos não têm valor primitivo para retornar, portanto, simplesmente retornam a si mesmas.O objetivo de
toString
, por outro lado, é retornar uma representação em string de um objeto.Por exemplo:
Para a maioria das operações, o JavaScript tentará silenciosamente converter um ou mais operando (s) para o tipo necessário. Esse comportamento foi escolhido para tornar o JavaScript mais fácil de usar. JavaScript inicialmente não tinha exceções e isso também pode ter desempenhado um papel nesta decisão de design. Esse tipo de conversão implícita de tipo é chamado de coerção de tipo e é a base do sistema de tipo flexível (fraco) do JavaScript. As regras complicadas por trás desse comportamento têm o objetivo de mover a complexidade da conversão de tipos para a própria linguagem e para fora do seu código.
Durante o processo coercitivo, existem dois modos de conversão que podem ocorrer:
Number()
, .Boolean()
,String()
Etc.)Conversão para um primitivo
Ao tentar converter tipos não primitivos em primitivos a serem operados, a operação abstrata
ToPrimitive
é chamada com uma "dica" opcional de 'número' ou 'string'. Se a dica for omitida, a dica padrão é 'número' (a menos que o@@toPrimitive
método tenha sido substituído). Se a dica for 'string', elatoString
será tentada primeiro e , em seguida ,valueOf
setoString
não retornar um primitivo. Caso contrário, vice-versa. A dica depende da operação que solicita a conversão.O operador de adição não fornece nenhuma dica, então
valueOf
é tentado primeiro. O operador de subtração fornece uma dica de 'número', entãovalueOf
é tentado primeiro. As únicas situações que posso encontrar na especificação em que a dica é 'string' são:Object#toString
ToPropertyKey
, que converte um argumento em um valor que pode ser usado como uma chave de propriedadeConversão direta de tipo
Cada operador tem suas próprias regras para completar sua operação. O operador de adição será usado primeiro
ToPrimitive
para garantir que cada operando seja um primitivo; então, se qualquer operando for uma string, ele invocará deliberadamente a operação abstrataToString
em cada operando, para entregar o comportamento de concatenação de string que esperamos com as strings. Se, após aToPrimitive
etapa, ambos os operandos não forem strings, então a adição aritmética é executada.Ao contrário da adição, o operador de subtração não tem comportamento sobrecarregado e, portanto, invocará
toNumeric
cada operando tendo primeiro os convertido em primitivos usandoToPrimitive
.Assim:
Observe que o
Date
objeto intrínseco é único, pois é o único intrínseco a substituir o@@toPrimitive
método padrão , no qual a dica padrão é presumida como 'string' (em vez de 'número'). A razão para isso é que asDate
instâncias sejam convertidas em strings legíveis por padrão, em vez de seu valor numérico, para a conveniência do programador. Você pode substituir@@toPrimitive
em seus próprios objetos usandoSymbol.toPrimitive
.A grade a seguir mostra os resultados da coerção para o operador de igualdade abstrato (
==
) ( fonte ):Veja também .
fonte