¿Por qué {} + {} ya no es NaN en la consola de Chrome?

144

Hoy noté que Chrome 49 ya no sale NaNcuando escribes {}+{}en la consola. En su lugar, genera la cadena [object Object][object Object].

¿Por qué es esto? ¿Ha cambiado el idioma?

Filip Haglund
fuente
13
Parece que Chrome ahora trata esta operación como un concat de cadena en lugar de una adición. POR QUÉ eso es, no sé, por eso es un comentario, no una respuesta :) intente var e = {}; e.toString()y verá lo que quiero decir
user428517
19
"¿Ha cambiado el idioma?" No.
Felix Kling el
66
@FelixKling ¿ Cambiará el idioma? ...No. : c
gato
18
¿Quizás WATMAN tuvo algo que ver con eso?
rickster
1
@rickster así es como lo encontré. Estaba recreando eso para una presentación.
Filip Haglund

Respuestas:

152

Las devtools de Chrome ahora envuelven automáticamente todo lo que comienza {y termina }en un par de paréntesis implícito ( ver código ), para forzar su evaluación como una expresión. De esa manera, {}crea un objeto vacío ahora. Puede ver esto si vuelve al historial ( ), la línea anterior estará contenida (…).

¿Por qué? No lo sé, pero podría adivinar que reduce la confusión para los novatos que no saben sobre el bloque literal vs objeto literal, y también es más útil si solo quieres evaluar una expresión.

Y de hecho ese es el razonamiento, como se discutió en el error 499864 . Pura conveniencia. Y porque el nodo REPL también lo tenía ( ver código ).

Bergi
fuente
182
Estúpido Chrome, {a:1}),({b:2}debería arrojar un error, no producir un objeto.
Oriol
29
Eso es lo que sucede cuando analiza estructuras anidadas arbitrariamente profundas con regex stackoverflow.com/questions/1732348/…
Filip Haglund
44
No tengo idea de por qué, pero de alguna manera cuando veo mis mensajes allí me siento "famoso", aunque esa página es tan pública como esta: D Problema extraño de desbordamiento de pila. Aquí está mi respuesta anterior sobre el problema stackoverflow.com/questions/17268468/…
Benjamin Gruenbaum
3
No me gusta la implementación actual y planeo arreglarla. bugs.chromium.org/p/chromium/issues/detail?id=499864#c17
Zirak
1
@Zirak Buena suerte arreglando esa basura, en mi opinión, debe retirarse lo antes posible. Pero si desea mejorarlo, considere agregar una nueva línea antes de insertarla )en caso de que esté en un comentario, por ejemplo, {a:3} // :-}podría producir un objeto.
Oriol
44

Si usted choca con la flecha hacia arriba después de comprobar esto, se dará cuenta de que en lugar de {} + {}Muestra ({} + {}), que da lugar "[object Object][object Object]".

En comparación, en Firefox, {} + {}todavía se muestra NaN, pero si lo hace ({} + {})también se muestra "[object Object][object Object]".

Entonces, parece que Chrome agrega el paréntesis circundante automáticamente cuando ve esta operación.

J. Titus
fuente
22
Esta respuesta es correcta. pero wow, hombre, no estoy seguro de que me guste que Chrome haga eso. mal google.
user428517
1
@sgroves Me interesaría ver si esto es lo mismo en Canarias, y si se hizo a propósito o si es realmente un error.
J. Titus
8
{} + {}cuando no se "desinfecta" ({} + {})se trata como + {}porque {}se analiza como un bloque vacío.
Gregory Nisbet
77
¿Por qué devolvería NaN en primer lugar?
0x499602D2
25
@ 0x499602D2: Porque a menos que haga los parens (o de lo contrario haga que el analizador cambie a esperar una expresión en lugar de una declaración), la inicial {}es solo un bloque de código vacío y se ignora, dejándonos con +{}, que es un objeto unario +y vacío. inicializador +forzará su argumento a número, lo que implica convertir el objeto en un primitivo (que terminará siendo un toStringen este caso, lo que da como resultado "[object Object]"), y así obtenemos +"[object Object]"cuál es NaNporque "[object Object]"no se puede convertir a un número válido.
TJ Crowder
4

A partir de Chrome 54 con respecto a la consola:

📎- "Convertí ese bloque en un Objeto para ti" -Clippy Desafortunadamente, agregué la cita de Clippy. La consola no brinda información sobre lo que ha hecho por usted.

Las nuevas reglas son increíblemente simples, ahorrándonos la molestia de escribir laboriosamente estos 2 caracteres difíciles o=o 0,antes de pegar Object Literals en la consola:

  • Si tiene código que comienza con: espacios en blanco opcionales, (no se permiten comentarios) seguido de a {;
  • y ese código podría interpretarse como un objeto;
  • y ese objeto no es seguido por ningún otro código, a menos que:
  • el código después del primer objeto es un operador binario,
  • entonces puede haber tantas operaciones como desee incluyendo agrupaciones
  • siempre que el operador final tenga un objeto literal en la posición derecha;
  • y ese objeto final no se ha agrupado en parens
  • y ese código no termina con punto y coma
  • y no hay comentarios siguiendo el código (se permiten comentarios internos siempre que no estén en la posición inicial o final)
  • entonces y solo entonces su JavaScript (que puede o no ser un código válido) será reintegrado como un Objeto válido. No se le informará que su código ha sido reinterpretado.

{wat:1}),({wat:2} Finalmente es un error nuevamente.

{let i=0;var increment=_=>i++} está correctamente permitido, finalmente, que es una buena manera de hacer cierres.

Sin embargo, lo siguiente es incorrectamente un objeto, esto es solo una conveniencia como lo menciona @Bergi, ¡interpreta a JS incorrectamente para ayudarlo! La especificación dice que es un bloque con una declaración etiquetada "foo" con un literal 1 que no está asignado a nada.

{foo:1}

Lo anterior debe ser lo mismo que

if(1) {
    foo: 1
}

Lo siguiente se trata correctamente como un bloque ... ¡porque tiene un comentario delante!

//magic comment
{foo:1}

Asi es esto:

{foo:1}
//also magic

Este es un objeto:

{foo:
//not so magic comment
1}

Esto es un error

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

Asi es esto:

{foo:1}.foo

Esto esta bien:

1..wat

undefined

asi es esto:

['foo'][0]

El siguiente se interpreta correctamente como un objeto golpeado en la posición de expresión con una forma en 0,que generalmente nos aseguramos sin ambigüedades de que tenemos una expresión en lugar de una declaración.

0,{foo:1}.foo

No entiendo por qué envuelven el valor en parens. JS tiene algunas decisiones de diseño ridículas, pero tratar de hacer que se comporte mejor en esta situación no es realmente una opción, la consola necesita ejecutar JS correctamente, y debemos estar seguros de que Chrome no solo adivina que cree que realmente quería decir que hiciera algo más.

Si no le gustan los operadores de coma, puede usar la asignación

x = {foo:1}.foo

Porque tal como está

{} + {} + {}

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

;{} + {} + {}

"NaN[object Object]"

Loco y constante con lo que puedo lidiar ... loco e inconsistente, ¡no, gracias!

James Wakefield
fuente
un REPL no es el idioma, es un REPL. Transmite cadenas al idioma, entre otras cosas . Aquí hay varias cosas que Chrome REPL hace que el lenguaje en sí no hace . Son bastante útiles, así que estoy muy contento de que no se hayan quedado con el lenguaje simple.
gman
@gman A REPL Lee una cadena, la evalúa, imprime los resultados y luego se prepara para leer el siguiente fragmento de código dinámico. Nada en la página vinculada era JavaScript no válido. La variable "$ _" en el contexto de la consola es claramente una conveniencia que solo tiene sentido en un REPL. Sin embargo, "$ _" es un nombre de variable válido, el resto son funciones normales y clases invocadas con JavaScript normal.
James Wakefield
No estoy seguro cual es tu punto. Mi punto es que el lenguaje es una cosa, el entorno en el que se ejecuta es otra. Diste un ejemplo en tu respuesta. En JS {foo:1}y {foo:1}//producir lo mismo. En Chrome JS REPL no lo hacen. REPL está haciendo más que solo evaluar JS. Está procesando las cadenas y decidiendo diferentes cosas.
Gman
var x = eval('{a:1}')En JavaScript válido, x es ahora 1, no el objeto más intuitivo {a: 1}. Sí, eso es raro, pero no puedes cambiar el idioma porque hace cosas raras. Todo lo que no sean cadenas JSON se interpreta como JavaScript y se evalúa. Escribir 0,antes de pegar el JSON no es difícil, alternativamente, estaría contento con una advertencia de que la cadena se interpretó como un objeto en lugar de JavaScript por conveniencia.
James Wakefield