js中new的运算符优先级问题记录

最近换了部门,要从头开始看新部门的一个node.js项目,看项目框架的时候,被一个关于new的问题卡了一下,简化一下问题代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function task() {
console.log('ddd')
return this;
}

task.getName = function() {
this.a = 'cool'
console.log('kk')
}

task.prototype.getName = function () {
this.a = 'pu'
console.log(3);
};

var Task = {}
Task.t = task

new Task.t.getName()
new Task.t().getName()

上面的代码会打印什么呢?

1
2
3
4
5
6
7
8
new Task.t.getName() 
// 会打印出:
// kk

new Task.t().getName()
// 会打印出:
// dd
// 3

仔细想了想,主要是看new是对哪个构造函数进行构造操作了, 在MDN官网查了下操作符优先级,大概是搞明白原因了:

优先级 运算类型 关联性 例子
20 圆括号 n/a (a + b) * c
19 成员访问 从左到右 object.method
19 需要计算的成员访问 从左到右 object[“a”+”b”]
19 new 带参数列表 n/a new fun()
19 函数调用 从左到右 fun()
18 new 无参数列表 从右到左 new fun

从这里可以看出无参数列表的new操作符优先级是18, 成员访问操作符的优先级是19,
对于:new Task.t.getName()

step1:
new Task是无参数new操作,运算符是18,Task.t是成员访问,优先级是19,所以是优先进行Task.t操作,task == Task.t, 则表达式变为new task.getName()

step2:
同样因为优先级的原因(new task优先级18, task.getName优先级19),先执行task.getName得到函数,这里假设g = task.getName,所以,最终表达式变成了 new g()

1
2
3
4
5
// g 对应的函数定义
function() {
this.a = 'cool'
console.log('kk')
}

step3:
此时的表达式是一个带参数列表的new操作, 就是利用构造函数g,构造一个新对象,在执行构造过程中会打印出 ‘kk’, 并且,新构造出的对象含有一个属性a,属性a的值为’cool’

再来看看 new Task.t().getName():

step1: new Task优先级18, Task.t优先级19,task=Task.t表达式变为new task().getName()

step2: new task()为带参数列表new操作,优先级19,.成员访问优先级也是19, 从左到右执行,所以先执行构造函数task构造一个新底线t = new task(),之后的表达式变为 t.getName()

step3: 在step2构造生成t的时候,得到t.getName为如下函数:

1
2
3
4
function () {
this.a = 'pu'
console.log(3)
}

所以 表达式最终结果就是执行该函数, 为构造出的对象t增加一个a属性 = ‘pu’,同时打印:3

~~ end