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?

Filip Haglund
fonte
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 ).

Bergi
fonte
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.

J. Titus
fonte
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!

James Wakefield
fonte
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