2012-03-29 11 views
9

Nella console sia di FF e Chrome, {} è considerato indefinito fino esplicitamente valutati:Quando (e perché) è {} non definito in una console JavaScript?

{};  // undefined 
({}); // ▶ Object 

In realtà, è un po 'meno definito di quanto non definito - è apparentemente cattiva sintassi:

{} === undefined; // SyntaxError: Unexpected token === 
{}.constructor; // SyntaxError: Unexpected token . 

ma se non è dall'altra parte, nel qual caso va bene:

"[object Object]" == {}.toString(); // true 

O se non è la prima espressione:

undefined + undefined; // NaN 
{} + undefined;  // NaN 
undefined + {};  // "undefined[object Object]" 

Cosa dà?

+6

... Che cosa f {UNDEFINED}? non è proprio appropriato. Puoi riformulare? –

+0

Le console non si associano necessariamente al JS normale. So per esempio che (non ricordo se questa fosse la chrome o la console FF) che se si digita '$ (id)' si valuterà 'documento.getElementById (id) '(che romperebbe con jQuery per esempio). – Alxandr

risposta

6

Ok, ecco la mia risposta. Non c'è nulla di nuovo qui. Sto solo collegando (una bella copia di) le specifiche ECMAScript per la grammatica e mostrando alcune produzioni per mostrare "perché" analizza il modo in cui funziona. In ogni caso, il comportamento è ben definito secondo le regole grammaticali JavaScript/ECMAScript:. {} viene analizzato in modo diverso a seconda del "contesto" è in


Le JavaScript REPL S ("console") inizio per analizzare il codice nella produzione di grammatica Statement o "contesto di istruzione". (Questa è in realtà una bugia, inizia dalla produzione Program o SourceElements, ma aggiunge ulteriori costrutti da scavare.) Ecco una ripartizione grammaticale approssimativa con semplificazioni e omissioni; vedi il link qui sopra per più:

Statement 
    Block 
    ... 
    ExpressionStatement 

Block 
    # This is actually { StatementList[optional] }, but this is what 
    # it amounts to: * means "0 or more". 
    { Statement* } 

ExpressionStatement 
    # An ExpressionStatement can't start with "{" or "function" as 
    # "{" starts a Block and "function" starts a FunctionStatement. 
    [lookahead ∉ {{, function}]Expression ; 

Expression 
    # This is really PrimaryExpression; I skipped a few steps. 
    ... 
    (Expression) 

Così (quando nel "contesto dichiarazione"):

{} 
-> Block # with no StatementList (or "0 statements") 
-> Statement 

E:

({}) 
-> (Expression) 
-> Expression 
-> ExpressionStatement # omitted in productions below 
-> Statement 

Questo spiega anche perché undefined === {} analizza come EXPR === EXPR -> EXPR -> STMT e risultati in falso quando valutato. Lo {} in questo caso è in un "contesto di espressione".

Nel caso di {} === undefined viene analizzato come {}; === undefined o BLOCK; BOGUS -> STMT; BOGUS, che è un Errore di sintassi. Tuttavia, con l'aggiunta di parentesi questo cambia: ({} === undefined) viene analizzato come (EXPR === EXPR) -> (EXPR) -> EXPR -> STMT.

Nel caso di {} + "hi" viene analizzato come {}; + "hi" o BLOCK; + EXPR -> STMT; EXPR -> STMT; STMT, che è sintassi valida anche se è stupido (+ è unario in questo caso). Allo stesso modo, come sopra, "hi" + {} inserisce lo {} in un "contesto di espressione" e viene analizzato come EXPR + EXPR -> EXPR -> STMT.

La console JavaScript mostra solo il risultato dell'ultima istruzione, che è "non definita" (beh, "nulla" in realtà, ma non esiste) per un blocco vuoto {}. (Ciò potrebbe variare tra browser/ambienti e ciò che viene restituito in questo caso, ad esempio solo l'ultimo ExpressionStatement?)

Felice codifica.

1

Sembra che entrambe le console lo considerino una condizione ambigua quando l'espressione inizia con {. Forse è trattato come un blocco fittizio.

Prova questo:

{} // undefined 
undefined === {} // false 

Utilizzando {} come un diritto-mano-espressione rimuove l'ambiguità.

Inoltre è possibile vedere da:

{a:42} // 42 
{{a:42}} // 42 
{{{a:42}}} // 42 

che le parentesi esterne sono davvero trattati come un blocco vuoto.

E questa non sembra essere una funzionalità di console. Anche eval li tratta come quella, alludendo al fatto che la roba si digita nella console effettivamente ottenere valutata allo stesso modo che avrebbero quando passato a eval:

eval("{}") // undefined 
eval("{alert(42)}") // alerts 42 
+0

{} === undefined è un errore SyntaxE, perché? –

+0

@JS_Riddler, per lo stesso motivo è: '{alert (" hi ")} === undefined' –

+0

Scusa, intendevo avere' {} 'da solo. Corretta la risposta –

0

Il problema è che in alcuni casi, javascript vede { e} come apertura e chiusura di un/block /. Mentre in altri casi, {} è un oggetto. I casi dipendono davvero dal contesto.

10

Se si utilizzano le parentesi graffe da sole, non è un oggetto letterale, è un blocco di codice. Poiché il blocco di codice non contiene alcun codice, la sua valutazione risulta in undefined.

+0

Lo stesso vale per gli altri moduli che funzionano: in questi casi il '{}' appare come * espressione *. –

+0

Questo non spiega come "{} === undefined" è un errore di sintassi e "undefined === {}" non lo è. –

+1

@JS_Riddler Sì, sì. '{} === undefined' è analizzato come' {}; === undefined' come '{}' appare in una posizione in cui è * not * letto come espressione. '({} === undefined)' funzionerebbe. Questo perché, in quest'ultimo caso, il parser legge '{}' come oggetto letterale ("come espressione"). –

0

Doug Crockford si lamenta di questo. Quel WTF che stai ricevendo è dovuto all'operatore + stesso. È abituato sia all'aritmetica sia alla concatenazione. Nella tua ultima riga, stai vedendo l'operatore + convertire undefined e l'oggetto vuoto in stringhe e concatenarle.

+0

Questo non è il problema in questo caso. Prova: '{} +" fallisce perché {} è un blocco e non un'espressione "" e "" okay perché {} ora è un'espressione "+ {}'. –

+0

No, entrambi concatenano ... Il primo valuterà "[oggetto oggetto] fallisce perché {} è un blocco e non un'espressione" e il secondo "okay perché {} ora è un'espressione [oggetto oggetto]" –

+0

@ pst: non è un errore di sintassi. il primo su è in realtà: '{}; + "somestring" .. '. che prova a convertire la stringa in numero e ottieni 'NaN' –

2

Se si digita {} come input in qualsiasi console, non esiste un contesto per interpretare ciò che si desidera che le parentesi graffe significhi, a parte la posizione. dato che ogni input alla console viene interpretato come una nuova riga di codice, la parentesi graffa aperta viene vista come l'inizio di un nuovo blocco. La chiusura } è sintatticamente corretto, poiché un blocco vuoto viene spesso utilizzata in situazioni come questi:

try 
{ 
    //something 
} 
catch(e) 
{}//suppress error 

Quindi {} sarà sempre definita quando è sul lato sinistro, e mai sputo errori come un blocco vuoto è codice valido

+0

@pst, vero ... Ho modificato la mia risposta. –

0

JavaScript separa il concetto di istruzioni ed espressioni (lingue come C++ o Java fanno lo stesso).

Ad esempio if ... è una dichiarazione e x?y:z è un'espressione.

Le espressioni hanno un valore, le affermazioni no.

Un problema con la sintassi di Javascript è che {} può essere un'espressione (e in questo caso significa un costruttore di oggetto vuoto) o un'istruzione (e in questo caso significa un blocco di codice vuoto ... fondamentalmente un NOP) quindi, come viene interpretato dipende dal contesto.

Problemi correlati