最近换了部门,要从头开始看新部门的一个node.js项目,看项目框架的时候,被一个关于new的问题卡了一下,简化一下问题代码:
1 | function task() { |
上面的代码会打印什么呢?
1 | new Task.t.getName() |
仔细想了想,主要是看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 | function () { |
所以 表达式最终结果就是执行该函数, 为构造出的对象t增加一个a属性 = ‘pu’,同时打印:3
~~ end