objeto - ¿Por qué la evaluación de JavaScript necesita paréntesis para evaluar datos JSON?
string to json javascript (7)
Aprendí (de la manera más difícil) que necesito agregar paréntesis alrededor de datos JSON, como este:
stuff = eval(''('' + data_from_the_wire + '')'');
// where data_from_the_wire was, for example {"text": "hello"}
(En Firefox 3, al menos).
¿Cuál es la razón detrás de esto? Odio escribir código sin entender qué hay detrás del capó.
Depende del valor de data_from_the_wire
, en realidad. En la mayoría de los casos, su sintaxis es correcta, pero una línea que comienza con {
se analiza como una etiqueta y la suya no es válida. Si lo rodea con paréntesis, evita que el analizador malinterprete su expresión.
Solo un problema de análisis, realmente. Con cuerdas, números o funciones, no tendrías ese problema.
Una solución es evaluar siempre las instrucciones y no las expresiones. Puedes escribir
eval(''var stuff = {"text": "hello"}'');
En JavaScript, las llaves se usan para crear instrucciones de bloque:
{
var foo = "bar";
var blah = "baz";
doSomething();
}
Las líneas anteriores se pueden poner dentro de una cadena y evaluar sin problema. Ahora considera esto:
{
"foo": "bar",
"blah": "baz"
}
Los corchetes hacen que el motor de JavaScript piense que es una expresión de grupo, de ahí el error de sintaxis alrededor del carácter :
Cita de MDN ... Guía de JavaScript ... Literales de objetos :
No debe usar un literal de objeto al comienzo de una instrucción. Esto dará lugar a un error o no se comportará como espera, porque {se interpretará como el comienzo de un bloque.
La solución para envolver el objeto literal inside ()
funciona diciéndole al motor que trate su contenido como una expresión, no como una instrucción de bloque. Entonces esto no funciona:
({
var foo = "bar";
var blah = "baz";
doSomething(evil);
})
// parse error
Pero esto hace:
({
"foo": "bar",
"blah": "baz"
})
// returns object
Esto sucede porque sin llaves redondas JavaScript intenta interpretar {"text": ...
como una etiqueta y falla. Pruébalo en la consola y obtendrás un error de "etiqueta no válida".
No estoy seguro de la razón, pero analizo JSON utilizando la clase JSON de json.org . Es mucho más seguro que usar eval.
No sé, y en realidad estoy interesado en la respuesta a esto, pero supongo que sin los paréntesis los datos en data_from_the_wire
se interpretarían como un cierre. Tal vez los paréntesis obligan a la evaluación y, por lo tanto, la matriz asociativa es "devuelta".
Este es el tipo de adivinanza que lleva a los votos a favor aunque =).
EDITAR
Douglas Crockford menciona una ambigüedad de sintaxis en su sitio json.org , pero eso realmente no me ayudó.
Poner los paréntesis alrededor de data_from_the_wire
es efectivamente equivalente a
stuff = eval(''return '' + data_from_the_wire + '';'');
Si tuviera que evaluar sin los paréntesis, entonces se evaluaría el código, y si tenía alguna función nombrada dentro de ella, se definirían, pero no se devolverían.
Tomemos como ejemplo la capacidad de invocar una función tal como se ha creado:
(function() { alert(''whoot''); })()
Llamará a la función que acaba de definirse. Lo siguiente, sin embargo, no funciona:
function() { alert(''whoot''); }()
Entonces vemos que los paréntesis efectivamente convierten el código en una expresión que regresa, en lugar de solo codificar para ejecutar.
eval
acepta una secuencia de declaraciones de Javascript. El analizador de Javascript interpreta el token ''{'', que aparece dentro de una instrucción como el inicio de un bloque y no el inicio de un objeto literal.
Cuando encierra su literal en paréntesis como este: ({ data_from_the_wire })
está cambiando el analizador de Javascript al modo de análisis de expresión. El token ''{'' dentro de una expresión significa el inicio de una declaración literal de objeto y no un bloque, y por lo tanto, Javascript lo acepta como un literal de objeto.