Qualsiasi altra lingua diversa da JavaScript ha una differenza tra le posizioni iniziali delle parentesi graffe (stessa riga e riga successiva)?


91

Oggi, mentre leggevo a caso il libro O'Reilly sui modelli JavaScript, ho trovato una cosa interessante (pagina 27 per riferimento).

In Javascript, in alcuni casi, c'è una differenza se la posizione iniziale della parentesi graffa è 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

Qualche altra lingua là fuori ha un comportamento simile? Se è così, allora dovrei cambiare di sicuro la mia abitudine .. :)

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


1
Riprodotto in Chrome e IE9, buona cattura: P
gideon

4
La sensibilità allo spazio bianco può essere fatta funzionare --- guarda Python o in modalità linea fortran --- ma la sottile sensibilità allo spazio bianco è opera del diavolo. Gah! Questo è brutto come il make!
dmckee --- gattino ex moderatore

Questo è impressionante! Bella scoperta!
CheckRaise

Ora voglio sapere perché javascript si comporta in questo modo.
CheckRaise

4
@CheckRaise: riassumo le regole qui: blogs.msdn.com/b/ericlippert/archive/2004/02/02/…
Eric Lippert

Risposte:


53

Qualsiasi linguaggio che non si basa su punti e virgola (ma invece su newline) per delimitare le istruzioni potenzialmente lo consente. Considera Python :

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

Potresti essere in grado di costruire un caso simile in Visual Basic, ma dalla parte superiore della mia testa non riesco a capire come perché VB è piuttosto restrittivo in cui i valori possono essere inseriti. Ma quanto segue dovrebbe funzionare, a meno che l'analizzatore statico non si lamenti di codice non raggiungibile:

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 menzionato, Ruby ha la stessa proprietà. PHP, C, C ++ e Java non lo fanno semplicemente perché scartano la nuova riga come spazi bianchi e richiedono punti e virgola per delimitare le istruzioni.

Ecco il codice equivalente dell'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 non consente mai a un'istruzione di estendersi su più righe a meno che non si utilizzi la sequenza di continuazione di riga "_".
phoog

2
Ok ritiro il commento precedente perché ho appena guardato le specifiche ci sono alcuni contesti in cui VB.NET supporta le continuazioni di riga implicite. Dubito che qualsiasi programmatore VB esperto considererebbe questo esempio un "gotcha", tuttavia, poiché è abbastanza ovvio Throwe ex.GetBaseException()sono linee logiche separate. Più specificamente, poiché Basic utilizza storicamente le linee per delimitare le sue istruzioni, un "gotcha" sarebbe più probabilmente una situazione in cui un programmatore pensa di aver creato una nuova istruzione su una nuova linea logica, ma non l'ha fatto.
phoog

@phoog Vero, non è assolutamente un trucco.
Konrad Rudolph

40

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

Quindi fondamentalmente il problema non è la posizione delle parentesi graffe (che qui rappresentano un oggetto letterale, non un blocco di codice come nella maggior parte delle lingue), ma questa piccola "caratteristica" che forza il tuo primo esempio a return ;=> undefined. Puoi controllare il comportamento di return nelle specifiche ES5 .

Per altre lingue che hanno un comportamento simile, controlla la risposta di Konrad .


5
Risposta altamente votata, ma in realtà è sbagliata, mi dispiace. La spiegazione è carina, ma correggi l'errore.
Konrad Rudolph

La parte su JavaScript non è sbagliata, il modo in cui si comporta in questo modo è a causa dell'inserimento del punto e virgola che forza la undefinedrestituzione. Ho scritto la parte sulle altre lingue con prefisso afaik , quindi prendila con le pinze :).
Alex Ciminian

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 lo fa . Ecco perché provoca così tanti trucchi.
ruakh

26

Più probabilmente. Il linguaggio di programmazione go di Google mostra un comportamento molto simile (anche se con effetti diversi). Come spiegato lì:

In effetti, ciò che accade è che il linguaggio formale utilizza i punti e virgola, proprio come in C o Java, ma vengono inseriti automaticamente alla fine di ogni riga che assomiglia alla fine di un'istruzione. Non è necessario digitarli da soli.

..snip ...

Questo approccio consente di ottenere codice dall'aspetto pulito e privo di punti e virgola. L'unica sorpresa è che è importante mettere la parentesi graffa di apertura di un costrutto come un'istruzione if sulla stessa riga dell'if; se non lo fai, ci sono situazioni che potrebbero non essere compilate o potrebbero dare il risultato sbagliato. La lingua impone in una certa misura lo stile delle parentesi graffe.

Segretamente, penso che Rob Pike volesse solo una scusa per richiedere lo stile One True Brace.


10
Fantastico, non lo sapevo :). Personalmente, non credo che l'inserimento automatico del punto e virgola sia una buona idea. Può introdurre piccoli bug che le persone inesperte con la lingua avranno difficoltà a capire. Se vuoi scrivere codice senza punto e virgola, preferisco il metodo Python.
Alex Ciminian

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

Vorrei votare, tranne per il fatto che la tua seconda frase è così completamente sbagliata che mi fa venir voglia di votare. Immagino che si annullino. ;-)
ruakh

1
@ruakh intendi "vai fa esattamente questo" o ti riferivi alla battuta su Rob Pike? Nel primo caso, potrei riformulare in "vai mostra lo stesso comportamento", nel secondo, mi dispiace se il mio debole senso dell'umorismo offende;)
Dave

1
Voglio dire "Go fa esattamente questo". La proposta originale per l'inserimento del punto e virgola di Go contrasta esplicitamente con quella di JavaScript, spiegando: "Questa proposta potrebbe ricordarti la regola del punto e virgola opzionale di JavaScript, che in effetti aggiunge punti e virgola per correggere gli errori di analisi. La proposta di Go è profondamente diversa", e cioè abbastanza vero, a tutti i livelli: funziona in modo diverso, ha effetti diversi e non ha quasi trucchi. (L'applicazione OTBS, sebbene fastidiosa, non è un trucco, poiché è un requisito coerente in tutto il codice Go.)
ruakh

14

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

return
{
     name: 'rajat'
};

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


6

FWIW, JSLint riporta diversi avvisi con quella 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

Il primo linguaggio in cui mi sono imbattuto in questo è stato awk (che ha anche la sua parte di sintassi "stranezze"; punti e virgola opzionali, concatenazione di stringhe utilizzando solo spazi bianchi e così via ...) Penso che i designer di DTrace, che hanno basato la sintassi D in modo approssimativo su awk, avevo abbastanza buon senso da NON copiare queste caratteristiche, ma non riesco a ricordare dalla parte superiore della mia testa. Un semplice esempio (contando il numero di tag ENTITY 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 invece questo piccolo script fosse scritto con la parentesi graffa su una riga propria, ecco cosa accadrebbe:

$ 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
$ 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.