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

IT技术 javascript new-operator
2021-02-01 10:04:43

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

const obj = new Foo;

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

const obj = new Foo();

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

6个回答

引用大卫弗拉纳根1

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

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

...

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

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


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

我发现许多 JavaScript 开发人员使用括号只是因为“工具 (JSLint) 告诉他们这样做”很有趣,特别是考虑到developer.mozilla.org/en-US/docs/Web/JavaScript/Guide上的示例/...,来自“发明了 <expletive> 语言的人”不要new Class对无参数构造函数使用任何括号如果这不是拼写“自以为是”,我不知道什么是......
2021-03-22 10:04:43
如果你想消除犯错的可能性,你应该使用(new Object).func(). 但我认为使用额外的括号和额外的等号,如==vs ===,这是不学习语言的糟糕借口。
2021-03-28 10:04:43
为什么 JSLint 鼓励使用括号?
2021-04-03 10:04:43
@ack 好吧,如果没有看到语言的发明者展示他们语言的某些特性(在这种情况下,省略构造函数上的括号的选项)会很奇怪如果他们没有添加该功能,我们就不会首先询问是否应该使用它。不使用它的一个实际原因是:new Object.func()不等同于new Object().func(). 通过始终包含括号,消除了犯此错误的可能性。
2021-04-04 10:04:43
我想它只是被认为更一致。
2021-04-08 10:04:43

两者有以下区别:

  • new Date().toString() 完美运行并返回当前日期
  • new Date.toString()抛出“类型错误:Date.toString 不是构造函数

它发生是因为new Date()new Date具有不同的优先级。根据MDN,我们感兴趣的 JavaScript 运算符优先级表的部分如下所示:

优先级 操作员类型 关联性 运营商
18 成员访问
计算成员访问
new(带参数列表)
从左到右
从左到右 不
适用
… . …
… [ … ]
new … ( … )
17 函数调用
new(无参数列表)
从左到右
从右到左
… ( … )
new …

从这张表可以看出:

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

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

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

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

    new Date.toString()抛出“ TypeError: Date.toString is not a constructor ”因为.优先级高于new Date(并且高于“函数调用”)并且表达式计算为(new (Date.toString))()

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

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


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

知道所有这些,可以假设这new Foo()是首选。

终于有人真正回答了问题并指出了细微差别!
2021-03-18 10:04:43
很好的解释,但我不同意结论,并且仍然认为如果你懂你的语言,不使用括号就好了。顺便说一句,如果您不知道 JS 优先级,您也可以使用(new Date).toString(),相同的字符数,并且比new Date().toString.
2021-03-22 10:04:43
解释得很好,提供了为什么new Foo()应该优先于new Foo. 迄今为止最好的答案。
2021-03-23 10:04:43
哇谢谢。让我想起另一种语言en.wikipedia.org/wiki/Brainfuck
2021-03-30 10:04:43
很棒的答案,优先表和随附的解释使它完全清楚。很高兴你解释了这如何让写作new Object().something()(new Object()).something().
2021-04-04 10:04:43

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

如果不需要它们,我会说添加它们是语法糖。:)
2021-03-15 10:04:43
我会说语法盐,但是 ymmv。
2021-04-09 10:04:43

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

var someVar = myFunc; // this assigns the function myFunc to someVar
var someOtherVar = myFunc(); // this executes myFunc and assigns the returned value to someOtherVar
如果您习惯于省略分号,问题就更大了。;-)
2021-03-11 10:04:43

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]] 内部方法的结果,不提供参数(即一个空的参数列表)。”
2021-03-26 10:04:43