Possiamo omettere le parentesi quando si crea un object usando l’operatore “nuovo”?

Ho visto oggetti creati in questo modo:

const obj = new Foo; 

Ma ho pensato che le parentesi non fossero opzionali durante la creazione di un object:

 const obj = new Foo(); 

Il precedente modo di creare oggetti è valido e definito nello standard ECMAScript? Ci sono delle differenze tra il precedente modo di creare oggetti e quello successivo? Si preferisce l’altro?

Citando David Flanagan 1 :

Come caso speciale, solo per il new operatore, JavaScript semplifica la grammatica consentendo di omettere la parentesi se non ci sono argomenti nella chiamata di funzione. Ecco alcuni esempi che utilizzano il new operatore:

 o = new Object; // Optional parenthesis omitted here d = new Date(); ... 

Personalmente, uso sempre la parentesi, anche quando il costruttore non accetta argomenti.

Inoltre, JSLint può ferire i tuoi sentimenti se si omette la parentesi. Segnala Missing '()' invoking a constructor e sembra che non ci sia un’opzione per lo strumento per tollerare l’omissione di parentesi.


1 David Flanagan: JavaScript la Guida definitiva: 4a edizione (pagina 75)

Ci sono differenze tra i due:

  • new Date().toString() funziona perfettamente e restituisce la data corrente
  • new Date.toString() lancia ” TypeError: Date.toString non è un costruttore

Succede perché la new Date() e la new Date hanno una precedenza diversa. Secondo MDN, la parte della tabella di precedenza degli operatori JavaScript che ci interessa è simile a:

 ╔════════════╦═════════════════════════════╦═══════════════╦═════════════╗ ║ Precedence ║ Operator type ║ Associativity ║ Operators ║ ╠════════════╬═════════════════════════════╬═══════════════╬═════════════╣ ║ 18 ║ Member Access ║ left-to-right ║ … . … ║ ║ ║ Computed Member Access ║ left-to-right ║ … [ … ] ║ ║ ║ new (with argument list) ║ n/a ║ new … ( … ) ║ ╠════════════╬═════════════════════════════╬═══════════════╬═════════════╣ ║ 17 ║ Function Call ║ left-to-right ║ … ( … ) ║ ║ ║ new (without argument list) ║ right-to-left ║ new … ║ ╚════════════╩═════════════════════════════╩═══════════════╩═════════════╝ 

Da questa tabella segue che:

  1. new Foo() ha precedenza più alta quindi new Foo

    new Foo() ha la stessa precedenza di . operatore

    new Foo ha un livello inferiore prima di allora . operatore

    new Date().toString() funziona perfettamente perché valuta come (new Date()).toString()

    new Date.toString() genera ” TypeError: Date.toString non è un costruttore ” perché . ha precedenza più alta quindi new Date (e più in alto poi “Chiamata Funzione”) e l’espressione valuta come (new (Date.toString))()

    La stessa logica può essere applicata all’operatore … [ … ] .

  2. new Foo ha associatività da destra a sinistra e per la new Foo() “associatività” di new Foo() non è applicabile. Penso che in pratica non faccia alcuna differenza. Per ulteriori informazioni vedi questa domanda SO


Si preferisce l’altro?

Sapendo tutto ciò si può supporre che sia preferito il new Foo() .

Non penso che ci sia alcuna differenza quando si utilizza l’operatore “nuovo”. Fai attenzione ad entrare in questa abitudine, in quanto queste due righe di codice NON sono le stesse:

 var someVar = myFunc; // this assigns the function myFunc to someVar var someOtherVar = myFunc(); // this executes myFunc and assigns the returned value to someOtherVar 

Se non hai argomenti da passare, le parentesi sono facoltative. Ometterli è solo zucchero sintattico.

https://people.mozilla.org/~jorendorff/es6-draft.html#sec-new-operator-runtime-semantics-evaluation

Ecco la parte della specifica ES6 che definisce come funzionano le due varianti. La variante senza parentesi passa una lista di argomenti vuota.

È interessante notare che le due forms hanno diversi significati grammaticali. Questo succede quando si tenta di accedere a un membro del risultato.

 new Array.length // fails because Array.length is the number 1, not a constructor new Array().length // 0 

Non c’è differenza tra i due.