web-dev-qa-db-fra.com

Peut-on omettre les parenthèses lors de la création d'un objet à l'aide de l'opérateur "nouveau"?

J'ai vu des objets créés de cette façon:

const obj = new Foo;

Mais je pensais que les parenthèses ne sont pas facultatives lors de la création d'un objet:

const obj = new Foo();

L'ancienne façon de créer des objets est-elle valide et définie dans la norme ECMAScript? Existe-t-il des différences entre l'ancienne façon de créer des objets et la dernière? Est-ce que l'un est préféré à l'autre?

213
Behrang

Citant David Flanagan1:

Comme cas spécial, pour l'opérateur new uniquement, JavaScript simplifie la grammaire en permettant d'omettre la parenthèse s'il n'y a pas d'arguments dans l'appel de fonction. Voici quelques exemples utilisant l'opérateur new:

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

...

Personnellement, j'utilise toujours la parenthèse, même lorsque le constructeur ne prend aucun argument.

De plus, JSLint peut blesser vos sentiments si vous omettez la parenthèse. Il signale Missing '()' invoking a constructor, et il ne semble pas y avoir d'option pour que l'outil tolère l'omission de parenthèses.


1 David Flanagan: JavaScript le guide définitif: 4e édition (page 75)

221
Daniel Vassallo

Il existe des différences entre les deux:

  • new Date().toString() fonctionne parfaitement et retourne la date actuelle
  • new Date.toString() lance " TypeError: Date.toString n'est pas un constructeur "

Cela se produit parce que new Date() et new Date Ont une priorité différente. Selon MDN la partie du tableau de priorité des opérateurs JavaScript qui nous intéresse ressemble à:

╔════════════╦═════════════════════════════╦═══════════════╦═════════════╗
║ 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 …       ║
╚════════════╩═════════════════════════════╩═══════════════╩═════════════╝

Il ressort de ce tableau que:

  1. new Foo() a une priorité plus élevée que new Foo

    new Foo() a la même priorité que l'opérateur .

    new Foo A un niveau de priorité inférieur à l'opérateur .

    new Date().toString() fonctionne parfaitement car il est évalué comme (new Date()).toString()

    new Date.toString() lance " TypeError: Date.toString n'est pas un constructeur " car . a une priorité plus élevée que new Date (Et supérieur à "Appel de fonction") et l'expression est évaluée comme (new (Date.toString))()

    La même logique peut être appliquée à l'opérateur … [ … ].

  2. new Foo A associativité de droite à gauche et pour new Foo() "associativité" n'est pas applicable. Je pense que dans la pratique, cela ne fait aucune différence. Pour plus d'informations, voir this SO question


Est-ce que l'un est préféré à l'autre?

Sachant tout cela, on peut supposer que new Foo() est préférable.

63
traxium

Je ne pense pas qu'il y ait de différence lorsque vous utilisez le "nouveau" opérateur. Soyez prudent lorsque vous prenez cette habitude, car ces deux lignes de code ne sont PAS les mêmes:

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

Si vous n'avez pas d'arguments à passer, les parenthèses sont facultatives. Les omettre n'est que du sucre syntaxique.

13
Josh

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

Voici la partie de la spécification ES6 qui définit le fonctionnement des deux variantes. La variante sans parenthèses passe une liste d'arguments vide.

Fait intéressant, les deux formes ont des significations grammaticales différentes. Cela apparaît lorsque vous essayez d'accéder à un membre du résultat.

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

Il n'y a aucune différence entre les deux.

3
Ivan