关于javascript:在使用“new”运算符创建对象时,我们可以省略括号吗?

Can we omit parentheses when creating an object using the “new” operator?

我见过这样创建的对象:

1
const obj = new Foo;

但我认为在创建对象时括号不是可选的:

1
const obj = new Foo();

前一种创建对象的方法是否有效并在ECMAScript标准中定义?前一种创建对象的方式和后一种创建对象的方式有什么区别吗?一个比另一个更受欢迎吗?


引用大卫·弗拉纳加1:

As a special case, for the new operator only, JavaScript simplifies the grammar by allowing the parenthesis to be omitted if there are no arguments in the function call. Here are some examples using the new operator:

1
2
3
4
o = new Object;  // Optional parenthesis omitted here
d = new Date();  

...

就我个人而言,我总是使用括号,即使构造函数不接受参数。

此外,如果省略括号,jslint可能会伤害您的感情。它报告了Missing '()' invoking a constructor,并且似乎没有一个工具可以容忍括号省略的选项。

1大卫·弗拉纳根:javascript最终指南:第4版(第75页)


两者之间存在差异:

  • new Date().toString()工作正常,返回当前日期
  • new Date.toString()抛出"typeerror:date.toString不是构造函数"

这是因为new Date()new Date具有不同的优先级。根据MDN,我们感兴趣的javascript操作符优先表的一部分如下:

1
2
3
4
5
6
7
8
9
10
╔════════════╦═════════════════════════════╦═══════════════╦═════════════╗
║ 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 …       ║
╚════════════╩═════════════════════════════╩═══════════════╩═════════════╝

从下表可以看出:

  • new Foo()的优先级高于new Foo

    new Foo().运算符具有相同的优先级

    new Foo的优先级比.运算符低一级。

    new Date().toString()工作得很好,因为它的评估结果是(new Date()).toString()

    new Date.toString()抛出"typeerror:date.toString不是构造函数",因为.的优先级高于new Date(高于"函数调用"),表达式的计算结果为(new (Date.toString))()

    同样的逻辑也适用于… [ … ]运算符。

  • new Foo具有从右向左的关联性,对于new Foo()不适用"关联性"。我认为在实践中没有任何区别。有关更多信息,请参阅此问题

  • Is one preferred over the other?

    知道这些,我们可以假定,最好是new Foo()


    我认为当你使用"新"操作符时没有什么区别。注意养成这个习惯,因为这两行代码不一样:

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


    如果没有要传递的参数,则括号是可选的。省略它们只是语法上的甜头。


    https://people.mozilla.org/~jorendorff/es6 draft.html sec新操作员运行时语义评估

    这是ES6规范的一部分,它定义了这两个变体的操作方式。无括号变量传递一个空参数列表。

    有趣的是,这两种形式有不同的语法意义。当您尝试访问结果的成员时,会出现这种情况。

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


    两者没有区别。