考察函数和作用域的 PRIORITY,以及 new 在执行时的一些机制。需要结合执行上下文来分析函数和变量声明的顺序与优先级。
题目
function Foo() {
getName = function () {
console.log("11=>", 11)
}
return this
}
Foo.getName = function () {
console.log("22=>", 22)
}
Foo.prototype.getName = function () {
console.log("33=>", 33)
}
var getName = function () {
console.log("44=>", 44)
}
function getName() {
console.log("55=>", 55)
}
Foo.getName()
getName()
Foo().getName()
getName()
new Foo.getName()
new Foo().getName()
new new Foo().getName()
// 22=> 22
// 44=> 44
// 11=> 11
// 11=> 11
// 22=> 22
// 33=> 33
// 33=> 33
分析
- Foo.getName() 调用的是 Foo 上的静态方法,输出 22。
- 第一次调用 getName() 输出 44,调用的是全局作用域下声明的 getName 变量函数。
- Foo().getName() 输出 11,Foo() 构造函数内部声明的 getName 变量,优先级最高。
- 第二次调用 getName() 输出 11,因为被 Foo() 内的 getName 覆盖了。
- new Foo.getName() 输出 22,new 执行的是 Foo 上的静态方法。
- new Foo().getName() 输出 33,new Foo() 创建了一个实例,调用的是原型上的方法。
- new new Foo().getName() 也输出 33,新的语法并没有改变其机制,仍然执行原型上的方法。
收获
- 远算优先级
- 分组(…)19
- 成员访问(a.b) ,new(带参数了;列表),函数调用,可选链 优先级较高 为 18
- new(无参数列表) 17 new Foo 属于无参数列表
- 后置递增 /递减 16
- 赋值 (从右到左) 2
- new 关键字会进行如下的操作:
- 创建一个空的简单 JavaScript 对象(即 {});
- 为步骤 1 新创建的对象添加属性 proto,将该属性链接至构造函数的原型对象;
- 将步骤 1 新创建的对象作为 this 的上下文;
- 如果该函数没有返回对象,则返回 this。
.
和new
的优先级
- . 当 new 和 . 同时出现时,new 的优先级更高,例如:
new Foo().getName()
这里 new Foo()会先执行。 - 当 . 在 new 的参数位置时,. 的优先级更高,例如:
new Foo.getName()
这里 Foo.getName 会先解析。 - 当 . 不在 new 的参数位置时,new 的优先级更高。
这么设定优先级主要基于以下考虑:
- new 作为创建实例的运算符,应该先执行。
- . 在 new 的参数位置时,要先解析出一个静态方法。
- . 不在参数位置时,应该作用于 new 创建的实例上。