2009-06-08 6 views
33

que he aprendido (la forma más dura) que tengo que añadir entre paréntesis los datos JSON, como esto:¿Por qué la evaluación de JavaScript necesita paréntesis para evaluar datos JSON?

stuff = eval('(' + data_from_the_wire + ')'); 
// where data_from_the_wire was, for example {"text": "hello"} 

(En Firefox 3, por lo menos).

¿Cuál es la razón detrás de esto? Odio escribir código sin entender qué hay detrás del capó.

+1

Veo que no es un hablante nativo de Inglés, pero '(' y ')' son paréntesis. Puede ayudar a otras personas a encontrar su publicación si corrige esto. –

Respuesta

38

Poner los paréntesis alrededor de data_from_the_wire es efectivamente equivalente a

stuff = eval('return ' + data_from_the_wire + ';'); 

Si se va a eval sin los paréntesis, a continuación, el código sería evaluado, y si tenían ninguna funciones con nombre dentro de él los estaría definido , pero no devuelto

tomar como ejemplo la posibilidad de llamar a una función tal y como de han sido creado:

(function() { alert('whoot'); })() 

llamará a la función que acaba de ser definido. A continuación, sin embargo, no funciona:

function() { alert('whoot'); }() 

Y vemos que los paréntesis a continuación de manera efectiva a su vez código en una expresión que devuelve, en lugar de sólo la ejecución de código.

+3

+1 Explicación muy clara. Gracias. –

+1

+1 por la misma razón que Oliver :) – Stefan

+4

La primera parte no es exactamente correcta; eval interpreta la cadena como código de nivel superior, por lo que el retorno no funciona. El problema con las funciones es similar a la pregunta original, porque es una ambigüedad entre una función * instrucción * y una función * expresión * (ver la respuesta de karim79). –

-2

No sé, y estoy realmente interesado en la respuesta a esto, pero mi hipótesis es 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, pero que en realidad no me ayuda.

10

No estoy seguro de la razón pero analizo JSON utilizando the JSON class de json.org. Es mucho más seguro que usar eval.

+5

¿Por qué el voto a favor? Parece una respuesta válida. Usar eval no es seguro. –

+0

No pregunta cómo usar eval correctamente para analizar JSON, pregunta por qué hay necesidad de paréntesis. –

+2

@ TimČas Me doy cuenta de que no estaba respondiendo la pregunta directamente, pero cuando alguien apunta con un arma al pie y pregunta por qué necesitan quitar la seguridad, primero les digo que apuntar con un arma al pie podría no ser una buena idea. –

62

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 objeto literal.

2

Esto sucede porque, sin llaves redondas, JavaScript intenta interpretar {"text": ... como a label y falla. Pruébalo en la consola y obtendrás un error de "etiqueta no válida".

1

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.

Simplemente 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. Puede escribir

eval('var stuff = {"text": "hello"}'); 
9

En JavaScript, entre llaves se utilizan para crear las instrucciones de bloque:

{ 
var foo = "bar"; 
var blah = "baz"; 
doSomething(); 
} 

Las líneas anteriores se pueden poner dentro de una cadena y eval uated sin problema. Ahora considere esto:

{ 
"foo": "bar", 
"blah": "baz" 
} 

Las llaves hacen que el motor de JavaScript a pensar que es una expresión de grupo, de ahí el error de sintaxis en torno al personaje :. Cita de MDN...JavaScript Guide...Object Literals:

No debe usar un literal de objeto al comienzo de una instrucción. Esto dará lugar a un error o no se comportará como esperaba, porque el { se interpretará como el comienzo de un bloque.

La solución para envolver el objeto literal dentro de () funciona diciéndole al motor que trate su contenido como una expresión, no como una instrucción de bloque. Así que esto no funciona:

({ 
var foo = "bar"; 
var blah = "baz"; 
doSomething(evil); 
}) 
// parse error 

Pero esto hace:

({ 
"foo": "bar", 
"blah": "baz" 
}) 
// returns object 
Cuestiones relacionadas