Por que {} + {} não é mais NaN no console do Chrome?


144

Hoje notei que o Chrome 49 não sai mais NaNquando você digita {}+{}no console. Em vez disso, gera a string [object Object][object Object].

Por que é isso? O idioma mudou?


13
parece que o chrome agora trata essa operação como uma concat da string em vez de uma adição. Por que isso é, eu não sei, é por isso que este é um comentário não é uma resposta :) tentar var e = {}; e.toString()e você verá o que quero dizer
user428517

19
"O idioma mudou?" Não
Felix Kling

6
@FelixKling Será que a alteração de idioma? ...não. : c
cat

18
Talvez WATMAN tenha algo a ver com isso?
Rickster

1
Rickster @ é assim que eu encontrei. Eu estava recriando isso para uma apresentação.
Filip Haglund 8/16

Respostas:


152

As ferramentas do Chrome agora envolvem automaticamente tudo o que começa {e termina com }um par implícito de parênteses ( consulte o código ), para forçar sua avaliação como uma expressão. Dessa forma, {}cria um objeto vazio agora. Você pode ver isso se voltar ao histórico ( ), a linha anterior estará contida (…).

Por quê? Não sei, mas acho que isso reduz a confusão para iniciantes que não sabem o que é literalmente bloco versus objeto, e também é mais útil se você quiser apenas avaliar uma expressão.

E, de fato, esse é o raciocínio, conforme discutido no bug 499864 . Pura conveniência. E porque o nó REPL também o tinha ( consulte o código ).


182
Chrome estúpido, {a:1}),({b:2}deve gerar um erro, não produzir um objeto.
Oriol #

29
É isso que acontece quando você analisar estruturas arbitrariamente profunda aninhadas com regex stackoverflow.com/questions/1732348/...
Filip Haglund

4
Não sei por que, mas, de alguma forma, quando vejo minhas mensagens lá, me sinto "famoso", embora essa página seja tão pública quanto esta: D Problema estranho no StackOverflow. Aqui está a minha resposta mais velhos sobre o problema stackoverflow.com/questions/17268468/...
Benjamin Gruenbaum

3
Não gosto da implementação atual e pretendo corrigi-la. bugs.chromium.org/p/chromium/issues/detail?id=499864#c17
Zirak 06/04

1
@ Zirak Boa sorte consertando esse lixo, IMO deve ser devolvido o mais rápido possível. Mas se você quiser melhorá-lo, considere adicionar uma nova linha antes da inserida ), caso esteja em um comentário, por exemplo, {a:3} // :-}ainda pode produzir um objeto.
Oriol

44

Se você acertar a seta para cima depois de verificar isso, você vai perceber que em vez de {} + {}ele exibe ({} + {}), o que resulta em "[object Object][object Object]".

Em comparação, no Firefox, {} + {}ainda é exibido NaN, mas se você o fizer ({} + {}), também será exibido "[object Object][object Object]".

Portanto, parece que o Chrome está adicionando os parênteses circundantes automaticamente quando vê essa operação.


22
esta resposta está correta. mas uau, cara, não tenho certeza se gosto desse cromo. google ruim.
user428517

1
@sgroves Eu estaria interessado em ver se isso é o mesmo no Canary, e se foi feito de propósito ou é realmente um bug.
314 Titus

8
{} + {}quando não "higienizado" ({} + {})é tratado como + {}porque {}é analisado como um bloco vazio.
Gregory Nisbet

7
Por que retornaria NaN em primeiro lugar?
0x499602D2

25
@ 0x499602D2: Porque, a menos que você faça o parens (ou faça com que o analisador espere uma expressão em vez de uma instrução), a inicial {}é apenas um bloco de código vazio e é desconsiderada, deixando-nos com +{}, que é um +objeto unário e vazio inicializador. +coagirá seu argumento ao número, o que envolve converter o objeto em um primitivo (que acabará sendo um toStringneste caso, resultando em "[object Object]") e, portanto, obtemos o +"[object Object]"que é NaNporque "[object Object]"não pode ser convertido em um número válido.
TJ Crowder

4

A partir do Chrome 54 em relação ao console:

"- "Eu converti esse bloco em um objeto para você" -Clippy Infelizmente, eu adicionei a citação Clippy. O console não fornece informações sobre o que fez por você.

As novas regras são incrivelmente simples, poupando o trabalho de digitar laboriosamente esses 2 charcters difíceis o=ou 0,antes de colar Literais de Objetos no console:

  • Se você tiver um código que comece com: espaço em branco opcional, (nenhum comentário permitido) seguido por a {;
  • e esse código pode ser interpretado como um objeto;
  • e esse objeto não é seguido por nenhum outro código, a menos que:
  • o código após o primeiro objeto é um operador binário,
  • pode haver quantas operações você desejar, incluindo agrupamentos
  • desde que o operador final tenha um literal de objeto na posição direita;
  • e esse objeto final não foi agrupado em parênteses
  • e esse código não é finalizado com ponto e vírgula
  • e não há comentários seguindo o código (comentários internos são permitidos desde que não estejam na posição inicial ou final)
  • então, e somente então, seu JavaScript (que pode ou não ser realmente um código válido) será novamente inserido como um objeto válido. Você não será informado de que seu código foi reinterpretado.

{wat:1}),({wat:2} É finalmente um erro novamente.

{let i=0;var increment=_=>i++} é corretamente permitido, finalmente, o que é uma ótima maneira de fazer fechamentos.

No entanto, o objeto a seguir é incorretamente incorreto; isso é tão conveniente quanto mencionado por @Bergi; ele interpreta JS errado para ajudá-lo! A especificação diz que é um bloco com uma declaração rotulada "foo" com um literal 1 que não está atribuído a nada.

{foo:1}

O acima deve ser o mesmo que

if(1) {
    foo: 1
}

O seguinte é tratado corretamente como um bloco ... porque ele tem um comentário à sua frente!

//magic comment
{foo:1}

Então é isso:

{foo:1}
//also magic

Este é um objeto:

{foo:
//not so magic comment
1}

Isto é um erro

//not so magic comment
{foo:1}.foo

Então é isso:

{foo:1}.foo

Isto é bom:

1..wat

undefined

então é isso:

['foo'][0]

O próximo é corretamente interpretado como um objeto atingido na posição de expressão com um 0,que geralmente é como garantimos inequivocamente que temos uma expressão em vez de uma declaração.

0,{foo:1}.foo

Não entendo por que eles agrupam o valor em parênteses. O JS tem algumas decisões de design ridículas, mas tentar torná-lo melhor nessa situação não é realmente uma opção, o console precisa executar o JS corretamente e precisamos ter certeza de que o chrome não está apenas supondo que acha que realmente significava fazer outra coisa.

Se você não gosta de operadores de vírgula, pode usar a atribuição

x = {foo:1}.foo

Porque como está

{} + {} + {}

"[object Object][object Object][object Object]"

;{} + {} + {}

"NaN[object Object]"

Louco e consistente eu posso lidar com ... louco e inconsistente não, obrigado!


um REPL não é o idioma, é um REPL. Passa as cordas para o idioma, entre outras coisas . Aqui estão algumas coisas que o Chrome REPL faz no próprio idioma . Eles são muito úteis, então estou muito feliz por não terem aderido apenas à linguagem simples.
gman

@ gman A REPL Lê uma string, Avalia-a, Imprime os resultados e depois se prepara para ler a próxima parte do código dinâmico. Nada na página vinculada era JavaScript inválido. A variável "$ _" com escopo definido no contexto do console é claramente uma conveniência que só faz sentido em um REPL. No entanto, "$ _" é um nome de variável válido, o restante são apenas funções e classes normais invocadas com JavaScript normal.
James Wakefield

Não tenho certeza qual é o seu ponto. Meu argumento é que a linguagem é uma coisa, o ambiente em que ela é executada é outra. Você deu um exemplo em sua resposta. Em JS {foo:1}e {foo:1}//produzir a mesma coisa. No Chrome JS REPL, eles não. O REPL está fazendo mais do que apenas avaliar o JS. Ele está processando as strings e decidindo fazer coisas diferentes.
gman 14/01

var x = eval('{a:1}')No JavaScript válido, x é agora 1, não o objeto mais intuitivo {a: 1}. Sim, isso é estranho, mas você não pode simplesmente mudar o idioma, porque ele faz coisas estranhas. Tudo, exceto as cadeias JSON, é interpretado como JavaScript e avaliado. Digitar 0,antes de colar o JSON não é difícil; alternativamente, eu ficaria feliz com um aviso de que a string foi interpretada como um objeto em vez de JavaScript por conveniência.
James Wakefield
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.