阿瑞斯的BLOG

js中new 实例化对象不带括号是错误写法吗?

关键词
new与属性访问的顺序 优先级 结合性 执行顺序 求值顺序

描述:

如果不是,那么和 new Class() 有什么区别吗?
来源:《基于 MVC 的 JavaScript 富应用》P7

new操作符不带括号

参考来源

ECMAScript 标准里关于 new 运算符 (11.2.2) 和 function calls 的描述是下面这一段:

11.2.2 The new Operator

The production NewExpression : new NewExpression is evaluated as follows:

Let ref be the result of evaluating NewExpression.
Let constructor be GetValue(ref).
If Type(constructor) is not Object, throw a TypeError exception.
If constructor does not implement the [[Construct]] internal method, throw a TypeError exception.
Return the result of calling the [[Construct]] internal method on constructor, providing no arguments (that is, an empty list of arguments).
The production MemberExpression : new MemberExpression Arguments is evaluated as follows:

Let ref be the result of evaluating MemberExpression.
Let constructor be GetValue(ref).
Let argList be the result of evaluating Arguments, producing an internal list of argument values (11.2.4).
If Type(constructor) is not Object, throw a TypeError exception.
If constructor does not implement the [[Construct]] internal method, throw a TypeError exception.
Return the result of calling the [[Construct]] internal method on constructor, providing the list argList as the argument values.

11.2.3 Function Calls

The production CallExpression : MemberExpression Arguments is evaluated as follows:

Let ref be the result of evaluating MemberExpression.
Let func be GetValue(ref).
Let argList be the result of evaluating Arguments, producing an internal list of argument values (see 11.2.4).
If Type(func) is not Object, throw a TypeError exception.
If IsCallable(func) is false, throw a TypeError exception.
If Type(ref) is Reference, then
If IsPropertyReference(ref) is true, then
Let thisValue be GetBase(ref).
Else, the base of ref is an Environment Record
Let thisValue be the result of calling the ImplicitThisValue concrete method of GetBase(ref).
Else, Type(ref) is not Reference.
Let thisValue be undefined.
Return the result of calling the [[Call]] internal method on func, providing thisValue as the this value and providing the list argList as the argument values.
The production CallExpression : CallExpression Arguments is evaluated in exactly the same manner, except that the contained CallExpression is evaluated in step 1.

NOTE The returned result will never be of type Reference if func is a native ECMAScript object. Whether calling a host object can return a value of type Reference is implementation-dependent. If a value of type Reference is returned, it must be a non-strict Property Reference.

结论

在 JavaScript 中,如果构造函数不带参数的话,new 的时候可以省略括号。

所以以下两种写法等价

1
2
var Person = new Class()
var Person = new Class

深入

但是下面这两种就是不同的

1
2
var f = new Foo.getName();
var f = new Foo().getName();

这里其实就考察了一个操作符的优先级(注意:指的是优先结合)和结合性:具体可以参考我的总结JavaScript运算符

当一个操作数同时位于一个操作符的右边和一个操作符的左边,应该如何添加括号 => 先看优先级

如果优先级相等的情况下,再看结合性,是左结合还是右结合以决定添加如何添加括号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Foo() {
getName = function () { console.log (1); };
return this;
}
Foo.getName = function () { console.log (2);};
Foo.prototype.getName = function () { console.log (3);};
var getName = function () { console.log (4);};
function getName() { console.log (5);}
Foo.getName(); // 2
getName(); // 4
Foo().getName(); //不是4 而是1
为什么是1?
其实这个代码也只有在浏览器才能运行,在 node 报错,原因就是 return this, 在 node 中返回的是 undefined, 所以会报错,而在浏览器中, this 会指向 window,并且由于Foo(),其中的 getName 并没有用 var 声明,所以隐式修改了全局变量getName 引用的值
// 重头戏
new Foo.getName(); //到底是 (new Foo).getName()还是new (Foo.getName())呢?可以看到,非有参构造, new + 操作数的优先级是18,所以说new (Foo.getName()),最终结果就是 2
new Foo().getName(); //到底是new (Foo().getName())还是 (new Foo()).getName()?注意不可能是new (Foo().getName())因为new + 操作数带括号默认表示有参数构造,视为一个整体,执行顺序一直都是从左到右的顺序依次计算所以结果应该是先实例化一个对象,再进行成员访问,即3 ,这里需要注意的是:带参数列表的 new ...(...) 看起来像是 new 后面跟了一个函数调用,但在判断运算符优先级时 new 运算是一个整体,不能把它分开

以上你可以学到什么?

  • 特殊的语法

  • new与属性访问的顺序