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


229

我看到过这样创建的对象:

const obj = new Foo;

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

const obj = new Foo();

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



更新的参考:ECMAScript 2017§12.3.3新的Opertator
RobG '17

TL; DR: 注意new a.b()与的不同之处new a().b()在于,在前一种情况下,a.b首先访问,而在后一种情况下,a首先创建一个新。
安德鲁

Answers:


238

引用David Flanagan 1

作为一种特殊情况,new仅对于运算符,JavaScript通过在函数调用中没有参数的情况下省略括号来简化语法。以下是使用new运算符的一些示例:

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

...

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

另外,如果省略括号,JSLint可能会伤害您的感觉。报告Missing '()' invoking a constructor,并且该工具似乎没有办法容忍括号遗漏。


1 David Flanagan:《JavaScript权威指南:第四版》(第75页)


6
为什么JSLint鼓励使用括号?
Randomblue

11
我想这只是更一致。
丹尼尔·瓦萨洛

12
我发现有趣的是,许多JavaScript开发人员仅因为“工具(JSLint)告诉他们使用括号”而使用括号,尤其是考虑到developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide上的示例/…,来自“发明<expletive>语言的人”,new Class对于无参数构造函数,不要使用任何括号。如果这没有拼写为“ opinionated”,我不知道这是什么...
确认

52
@ack好吧,如果没有看到语言的发明者展示其语言的某些功能,这很奇怪(在这种情况下,可以省略构造函数上的括号)。如果他们没有添加功能,我们就不会问是否应该首先使用它。不使用它的实际原因是:new Object.func()不等同于new Object().func()。通过始终加上括号,消除了犯此错误的可能性。
nmclean 2014年

2
如果您想消除犯错的可能性,则应该使用(new Object).func()。但是我考虑使用额外的括号和额外的等号,例如==vs中===,这是不学习语言的不好借口。
Jean Vincent

78

两者之间有区别:

  • 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        
╚════════════╩═════════════════════════════╩═══════════════╩═════════════╝

从该表可以得出:

  1. new Foo() 优先级高于 new Foo

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

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

    new Date().toString() 完美工作,因为它的评估为 (new Date()).toString()

    new Date.toString()抛出“ TypeError:Date.toString不是构造函数 ”,因为.它的优先级高于new Date(且高于“ Function Call”),并且表达式的计算结果为(new (Date.toString))()

    相同的逻辑可以应用于… [ … ]运算符。

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


是一个比另一个更好的选择吗?

知道了所有这些,就可以认为这new Foo()是首选。


4
最后,真正回答问题并指出细微差别的人!
gcampbell '16

哇谢谢。让我想起了另一种语言en.wikipedia.org/wiki/Brainfuck
John Henckel

解释清楚,提供了为什么new Foo()应该优先于的原因new Foo。迄今为止最好的答案。
CodeLama

很棒的答案,优先级表和随附的说明使它变得非常清楚。很高兴您能解释,这也使撰写new Object().something()和撰写文章变得很不错(new Object()).something()
LittleTiger

1
很好的解释,但我不同意结论,并且仍然认为如果您知道您的语言,则不使用括号就可以了。顺便说一句,如果您不知道JS优先级,也可以使用(new Date).toString(),字符数相同,并且比更加明确new Date().toString
Jean Vincent

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

1
如果您习惯省略分号,那么问题就更大了。;-)
RobG

13

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


8
我会说句法盐,但ymmv。
Thomas Eding

我会说,如果不需要它们,则添加它们是语法糖。:)
Cozzbie

8

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

它在ES5和ES3中也有很好的定义-“返回在构造函数上调用[[Construct]]内部方法的结果,不提供任何参数(即,空的参数列表)。”
本杰明·格林巴姆2014年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.