2009-06-08 8 views
33

ho imparato (il senso duro) che ho bisogno di aggiungere le parentesi intorno ai dati JSON, in questo modo:Perché l'avviso di JavaScript ha bisogno di parentesi per analizzare i dati JSON?

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

(In Firefox 3, almeno).

Qual è la ragione di questo? Odio scrivere codice senza capire cosa c'è dietro il cofano.

+1

Vedo che non sei un madrelingua inglese, ma '(' e ')' sono parentesi. Può aiutare altre persone a trovare il tuo post se lo correggi. –

risposta

38

Mettere le parentesi intorno data_from_the_wire è effettivamente equivalente a

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

Se si dovesse eval senza le parentesi, allora il codice sarebbe stato valutato, e se avete avuto tutte le funzioni con nome al suo interno quelli sarebbe definito , ma non restituito.

prendere come esempio la possibilità di chiamare una funzione così come è stato creato han:

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

chiamerà la funzione che è stato appena definito. Di seguito, però, non funziona:

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

Così vediamo che le parentesi in modo efficace si trasformano poi codice in un'espressione che restituisce, piuttosto che solo il codice per l'esecuzione.

+3

+1 Spiegazione molto chiara. Grazie. –

+1

+1 per lo stesso motivo di Oliver :) – Stefan

+4

La prima parte non è esattamente corretta; eval interpreta la stringa come codice di primo livello, quindi il ritorno non funziona. Il problema con le funzioni è simile a domanda iniziale, perché è un'ambiguità tra una funzione * * dichiarazione e una funzione * espressione * (vedi risposta di karim79). –

-2

Non so, e in realtà sono interessato alla risposta a questo, ma la mia ipotesi è che senza le parentesi i dati in data_from_the_wire sarebbero interpretati come una chiusura. Forse la parentesi forza la valutazione e quindi l'array associativo viene "restituito".

Questo è il tipo di ipotesi che porta a downvotes però =).

EDIT

Douglas Crockford menzioni un'ambiguità sintassi sul suo sito JSON ma che non mi ha veramente aiutato.

10

Non sono sicuro del motivo, ma analizzo JSON utilizzando the JSON class da json.org. È molto più sicuro che usare eval.

+5

Perché il downvote? Sembra una risposta valida. L'uso di eval non è sicuro. –

+0

Non sta chiedendo come usare eval correttamente per analizzare JSON, sta chiedendo perché c'è bisogno di parentesi. –

+2

@ TimČas mi rendo conto che non rispondeva alla domanda direttamente, ma quando qualcuno ti punta una pistola loro piede e chiede il motivo per cui hanno bisogno di rimuovere la sicurezza, li ho consigliare che punta una pistola al vostro piede potrebbe non essere una grande idea. –

62

eval accetta una sequenza di istruzioni Javascript. Il parser Javascript interpreta il token '{', che si verifica all'interno di un'istruzione come l'inizio di un blocco e non l'inizio di un oggetto letterale.

Quando si racchiude il letterale in parentesi come questo: ({ data_from_the_wire }) si sta commutando il parser di Javascript in modalità di analisi delle espressioni. Il token '{' all'interno di un'espressione indica l'inizio di una dichiarazione letterale dell'oggetto e non un blocco, e quindi Javascript lo accetta come oggetto letterale.

2

Questo accade perché senza parentesi tonde JavaScript tenta di interpretare {"text": ... come a label e ha esito negativo. Provalo in console e riceverai l'errore "etichetta non valida".

1

Dipende dal valore di data_from_the_wire, in realtà. Nella maggior parte dei casi la sintassi è corretta, ma una riga che inizia con { viene analizzata come etichetta e la tua non è valida.Se lo si circonda con una parentesi, impedisce al parser di interpretare erroneamente la propria espressione.

solo un problema di analisi, in realtà. Con stringhe, numeri o funzioni, non avresti quel problema.

Una soluzione è quella di sempre istruzioni eval e non espressioni. È possibile scrivere

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

In JavaScript, parentesi graffe vengono utilizzati per creare dichiarazioni di blocco:

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

Le linee di cui sopra possono essere messi all'interno di una stringa e eval uated senza problemi. Ora considerare questo:

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

Le parentesi graffe causano il motore JavaScript a pensare che sia un'espressione di raggruppamento, da qui l'errore di sintassi attorno al personaggio :. Citazione di MDN...JavaScript Guide...Object Literals:

Non dovrebbe usare un oggetto letterale all'inizio di una dichiarazione. Ciò porterà ad un errore o non comportarsi come ci si aspetta, perché il { saranno interpretati come l'inizio di un blocco.

La soluzione di avvolgere l'oggetto letterale all'interno () opere raccontando il motore di trattare i suoi contenuti come un'espressione, non come una dichiarazione di blocco. Quindi questo non funziona:

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

Ma questo fa:

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