使用"new"运算符创建对象时,我们可以省略括号吗?

Lam*_*bda 219 javascript new-operator

我看到过以这种方式创建的对象:

const obj = new Foo;
Run Code Online (Sandbox Code Playgroud)

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

const obj = new Foo();
Run Code Online (Sandbox Code Playgroud)

创建对象的前一种方法是否在ECMAScript标准中有效并定义?前一种创建对象的方式和后一种方法之间是否存在差异?一个比另一个更受欢迎吗?

Dan*_*llo 226

引用David Flanagan 1:

作为一种特殊情况,new仅对于运算符,如果函数调用中没有参数,则JavaScript允许省略括号,从而简化了语法.以下是使用new运算符的一些示例:

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

...
Run Code Online (Sandbox Code Playgroud)

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

此外,如果省略括号,JSLint可能会伤害您的感受.它报告Missing '()' invoking a constructor,并且该工具似乎没有选择容忍括号遗漏.


1 David Flanagan:JavaScript权威指南:第4版(第75页)

  • @ack嗯,看到语言的发明者展示他们语言的某些特征(在这种情况下,在构造函数中省略括号的选项)会很奇怪*.如果他们没有添加该功能,我们就不会问它是否应该首先使用.不使用它的一个实际原因是:`new Object.func()`不等同于`new Object().func()`.通过总是包括括号,消除了犯这个错误的可能性. (50认同)
  • 我觉得有趣的是,许多JavaScript开发人员使用括号只是因为"工具(JSLint)告诉他们这样做",特别是考虑到https://developer.mozilla.org/en-US/docs/Web上的示例/ JavaScript/Guide/Details_of_the_Object_Model,来自"发明<expletive>语言的人"不对无参数构造函数的`new Class`使用任何括号.如果这不是"舆论",我不知道是什么...... (12认同)
  • 我想它只是被认为更加一致. (11认同)
  • 为什么JSLint鼓励使用括号? (6认同)
  • 如果你想消除犯错的可能性,你应该使用```(new Object).func()```.但是我考虑使用额外的括号和额外的等号,如```==```vs``` ===```,这是一个不学习你的语言的错误借口. (2认同)

tra*_*ium 69

两者之间存在差异:

  • new Date().toString() 完美运作并返回当前日期
  • new Date.toString()抛出" TypeError:Date.toString不是构造函数 "

它发生是因为new Date()并且new Date具有不同的优先级.根据MDN我们感兴趣的JavaScript运算符优先级表的部分看起来像:

??????????????????????????????????????????????????????????????????????????
? 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 …       ?
??????????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

从下表可以看出:

  1. 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))()

    相同的逻辑可以应用于… [ … ]操作员.

  2. new Foo具有从右到左的相关性,并且new Foo()"相关性"不适用.我认为在实践中它没有任何区别.有关其他信息,请参阅 SO问题


一个比另一个更受欢迎吗?

知道了这一切,可以认为这new Foo()是首选.

  • 最后,有人真正回答了这个问题,并指出了微妙的差异! (3认同)

jba*_*bey 14

当您使用"new"运算符时,我认为没有任何区别.要小心养成这个习惯,因为这两行代码不一样:

var someVar = myFunc; // this assigns the function myFunc to someVar
var someOtherVar = myFunc(); // this executes myFunc and assigns the returned value to someOtherVar
Run Code Online (Sandbox Code Playgroud)

  • 如果您有省略分号的习惯,问题就更大了。;-) (2认同)

Jos*_*osh 13

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

  • 我会说句法盐,但是ymmv. (8认同)

gue*_*est 6

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

以下是ES6规范中定义两种变体如何运行的部分.无括号变体传递一个空参数列表.

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

new Array.length // fails because Array.length is the number 1, not a constructor
new Array().length // 0
Run Code Online (Sandbox Code Playgroud)