问题:
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();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
......
这道题考的知识面非常广,如题,考察到了js的声明提升、作用域、原型、new运算符以及运算符优先级的问题。
......
答案:
// f1
function Foo() {
getName = function () {
console.log(1)
};
return this;
}
// f2
Foo.getName = function () {
console.log(2)
}
// f3
Foo.prototype.getName = function () {
console.log(3)
}
// f4
var getName = function () {
console.log(4)
}
// f5
function getName() {
console.log(5)
}
Foo.getName(); // 2
// 调用Foo构造函数的私有属性getName, 上方执行的代码中f2处为getName属性进行了赋值操作,因此调用打印2。
Foo().getName(); // 1
// 首先调用Foo(),返回this, 全局函数Foo的this指向window,因此相当于window.getName()。调用Foo后运行其内部代码声明了一个全局的getName函数,覆盖掉了之前所有对其的全局声明(覆盖f4, f5)。因此调用打印1。
getName(); // 1
// 由于上面调用过Foo方法,使其内部的getName方法对之前所有挂载在window上的getName方法进行覆盖(覆盖f4, f5),因此调用打印1。
new Foo.getName(); // 2
// 原因同第一题,new运算符只是更改了this指向,但与调用打印结果无关。
new Foo().getName(); // 3
// 根据运算符优先级顺序, new Foo()会优先运算,返回一个this指向Foo本身的实例,而Foo内部并没有直接声明过this.getName的值,根据原型链的调用顺序,如果构造函数或者类自己本身没有这个方法,则通过原型链向上寻找,这里f3在其原型上绑定了getName方法,因此本题会访问到f3方法,调用打印3。
new new Foo().getName(); // 3
// 本题首先考察了运算符优先级的知识,这里首先运算的是new Foo(),返回指向其本身的Foo实例对象,再运算.getName(),此时可以参考上一题,通过原型链调用打印3,最后再计算第一个new,返回实例化后的getName函数。
运算符相关内容,建议访问https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
做详细了解。