91

Oggi, mentre leggevo a caso i modelli JavaScript del libro O'Reilly, ho trovato una cosa interessante (pagina 27 per riferimento).Qualche altra lingua diversa da JavaScript ha una differenza tra le posizioni di avvio delle parentesi graffe (stessa riga e riga successiva)?

In Javascript, in alcuni casi, c'è una differenza se la posizione di avvio del controvento è diversa.

function test_function1() { 
    return 
    { 
     name: 'rajat' 
    }; 
} 

var obj = test_function1(); 
alert(obj); //Shows "undefined" 

Mentre

function test_function2() { 
    return { 
     name: 'rajat' 
    }; 
} 

var obj = test_function2(); 
alert(obj); //Shows object 

JSfiddle Demo

Vuol qualsiasi altra lingua là fuori hanno un comportamento del genere? Se è così, allora dovrei cambiare la mia abitudine di sicuro .. :)

Sono principalmente preoccupato per PHP, C, C++, Java e ruby.

+1

Riprodotto in Chrome e IE9, buona pesca: P – gideon

+4

bianco spazio sensibilità può essere fatto per lavorare --- sguardo al pitone o modalità riga FORTRAN --- ma * * sottile sensibilità spazio bianco è il lavoro della diavolo. Gah! Questo è così male come fare! – dmckee

+0

Questo è impressionante! Bella scoperta! – CheckRaise

risposta

53

Qualsiasi linguaggio che non si basa sul punto e virgola (ma invece su una nuova riga) per delimitare le dichiarazioni lo consente potenzialmente. Considerare Python:

>>> def foo(): 
... return 
... { 1: 2 } 
... 
>>> def bar(): 
... return { 1: 2 } 
... 
>>> foo() 
>>> bar() 
{1: 2} 

Potreste essere in grado di costruire un caso simile in Visual Basic ma fuori dalla parte superiore della mia testa io non riesco a capire come, perché VB è piuttosto restrittiva in cui i valori possono essere posto. Ma il seguente dovrebbe funzionare, a meno che l'analizzatore statico lamenta codice su irraggiungibile:

Try 
    Throw New Exception() 
Catch ex As Exception 
    Throw ex.GetBaseException() 
End Try 

' versus 

Try 
    Throw New Exception() 
Catch ex As Exception 
    Throw 
    ex.GetBaseException() 
End Try 

dalle lingue che hai citato, Rubino ha la stessa proprietà. PHP, C, C++ e Java non semplicemente perché scartano newline come spazi bianchi e richiedono il punto e virgola per delimitare le istruzioni.

Ecco il codice equivalente dall'esempio Python in Ruby:

>> def foo 
>> return { 1 => 2 } 
>> end 
=> nil 
>> def bar 
>> return 
>> { 1 => 2 } 
>> end 
=> nil 
>> foo 
=> {1=>2} 
>> bar 
=> nil 
+2

Il tuo esempio di VB non fa proprio il punto perché VB * mai * consente a un'istruzione di estendersi su più righe a meno che non si usi la sequenza di continuazione della linea "_". – phoog

+2

Ok Ritiro il commento precedente perché ho appena visto le specifiche ci sono alcuni contesti in cui VB.NET supporta continuazioni di linea implicite. Dubito che qualsiasi programmatore VB esperto considererebbe questo esempio un "gotcha", tuttavia, poiché è abbastanza ovvio che 'Throw' e' ex.GetBaseException() 'sono linee logiche separate. Più in particolare, poiché Basic utilizza storicamente delle linee per delimitare le sue affermazioni, un "gotcha" sarebbe più probabilmente una situazione in cui un programmatore pensa di aver creato una nuova affermazione su una nuova linea logica, ma non lo ha fatto. – phoog

+0

@phoog Vero, non è assolutamente un trucco. –

40

L'interprete JavaScript aggiunge automaticamente uno ; alla fine di ogni riga se non ne trova uno (con alcune eccezioni, non inserendo qui :).

Quindi, in pratica il problema non è la posizione delle parentesi (che qui rappresentano un oggetto letterale, non un blocco di codice, come nella maggior parte delle lingue), ma questo piccolo 'caratteristica' che costringe il primo esempio a return ; =>undefined. È possibile controllare il comportamento di returnin the ES5 spec.

Per altre lingue con comportamento simile, vedere Konrad's answer.

+5

Risposta a risposta elevata, ma in realtà è sbagliata, scusa. La spiegazione è buona, ma ti preghiamo di correggere l'errore. –

+0

La parte relativa a JavaScript non è errata, il modo in cui si comporta come avviene a causa dell'inserimento del punto e virgola che obbliga a restituire "undefined". Ho scritto il pezzo delle altre lingue precedute da _afaik_, quindi prendilo con un pizzico di sale :). –

+5

Ma non è vero che JS inserisce un punto e virgola "alla fine di ogni riga" "con alcune eccezioni"; piuttosto, di solito * non * inserisce un punto e virgola, e ci sono solo pochi casi in cui * fa *. Ecco perché provoca così tanti trucchi. – ruakh

14

La risposta a questa domanda è abbastanza semplice. Qualsiasi lingua che ha "inserimento automatico punto e virgola" potrebbe essere in difficoltà su quella linea. Il problema con questo

return 
{ 
    name: 'rajat' 
}; 

..è che il motore js inserirà un punto e virgola dopo l'istruzione return; (e quindi, tornare undefined). Questo esempio è una buona ragione per aprire le parentesi graffe sempre sul lato destro e mai sul lato sinistro. Dato che hai già notato correttamente, se c'è una parentesi graffa nella stessa riga, l'interprete lo noterà e non può inserire un punto e virgola.

26

Più certamente. Il linguaggio di programmazione go di Google mostra un comportamento molto simile (anche se con effetti diversi). Come spiegato c'è:

In realtà, ciò che accade è che il linguaggio formale usa il punto e virgola, proprio come in C o Java, ma sono inseriti automaticamente alla fine di ogni riga che appare come la fine di una dichiarazione. Non è necessario digitarli da soli.

..snip ...

Questo approccio rende il codice pulito-cercando, senza virgola. L'unica sorpresa è che è importante mettere la parentesi di apertura di un costrutto come un'istruzione if sulla stessa riga di if; se non lo fai, ci sono situazioni che potrebbero non essere compilate o potrebbero dare il risultato sbagliato. Il linguaggio impone lo stile di coppia in una certa misura.

Segretamente, penso che Rob Pike volesse solo una scusa per richiedere l'One True Brace Style.

+10

Cool, non sapevo questo :). Personalmente, non penso che l'inserimento automatico del punto e virgola sia una buona idea. Può introdurre bug sottili che le persone inesperte con la lingua avranno difficoltà a capire. Se si desidera scrivere codice libero punto e virgola, preferisco il modo Python. –

+0

@Alex Anche le lingue senza * qualsiasi * punto e virgola (VB) hanno questa proprietà. E così fa Python, che a quanto pare preferisci, anche se lo gestisce in modo identico a JavaScript. –

+0

Avrei votato, tranne per il fatto che la tua seconda frase è così completamente sbagliata che mi fa venir voglia di parlare a rovescio. Immagino che si cancellino.;-) – ruakh

6

FWIW, JSLint rapporti diversi avvisi con questa sintassi:

$ jslint -stdin 
function foo(){ 
    return 
    { x: "y" }; 
} 
^D 
(3): lint warning: unexpected end of line; it is ambiguous whether these lines are part of the same statement 
    return 
........^ 

(3): lint warning: missing semicolon 
    { x: "y" }; 
..^ 

(3): lint warning: unreachable code 
    { x: "y" }; 
..^ 

(3): lint warning: meaningless block; curly braces have no impact 
    { x: "y" }; 
..^ 

(3): lint warning: use of label 
    { x: "y" }; 
.....^ 

(3): lint warning: missing semicolon 
    { x: "y" }; 
...........^ 

(3): lint warning: empty statement or extra semicolon 
    { x: "y" }; 
............^ 


0 error(s), 7 warning(s) 
1

La prima lingua in cui mi sono imbattuto in questo era awk (che ha anche la sua parte di "stranezze" di sintassi, semi-colonnello facoltativo, concatenazione di stringhe usando solo spazi bianchi e così via ...) Penso che i progettisti DTrace, che basavano la sintassi D liberamente su awk, avessero abbastanza senso per NON copiarli e caratteristiche, ma non riesco a ricordare in cima alla mia testa. Un semplice esempio (contando il numero di tag un'entità in un DTD, dal mio Mac):

$ cat printEntities.awk 
# This prints all lines where the string ENTITY occurs 
/ENTITY/ { 
    print $0 
} 
$ awk -f printEntities.awk < /usr/share/texinfo/texinfo.dtd | wc -l 
    119 

Se questo piccolo script invece sono stati scritti con la parentesi su una linea propria, questo è ciò che sarebbe accaduto:

$ cat printAll.awk 
# Because of the brace placement, the print statement will be executed 
# for all lines in the input file 
# Lines containing the string ENTITY will be printed twice, 
# because print is the default action, if no other action is specified 
/ENTITY/ 
{ 
    print $0 
} 
$ awk -f printAll.awk < /usr/share/texinfo/texinfo.dtd | wc -l 
    603 
$ /bin/cat < /usr/share/texinfo/texinfo.dtd | wc -l 
    484 
$