最近刷题遇到一个经典的 Foo 和 getName 面试题,看了几个解答,感觉有点不太容易懂,就按照自己的想法实现了一便,已作为笔记
题目如下
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();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
遇到这种题目,我们一定要有清醒的认知 首先我们画张图理清一下思维
首先js不会立即执行我们的代码 而是引擎通过词法分析将我们写的js代码转成可以执行的代码,接下来才是执行执行后的代码大概是
function getName(){
console.log(5);
}
var getName;
getName = function(){
console.log(4);
}
所以函数声明的getName会被覆盖掉 现在全局getName返回值为4
接下来代码执行 Foo.getName() 普通的调用 直接返回 2
第二个 getName() 变量提升修改了全局 现在返回 4
第三个 Foo().getName() 根据上图,我们当我们执行Foo() 会return 以合this 这个this就待变了全局window 再执行getName() 就会修改全局的getName 返回 1
第四个 getName() 我们修改了全局的getName 继续返回 1
第五个 new Foo.getName() 这个地方我们就需要了解js执行的优先级了
因为成员访问'.'的优先级比new高,所以先执行Foo.getName(),在来执行new,可看成=》new (Foo.getName()) (),new返回Foo.getName()的实例,根据第一张图可以知道 返回 2
第六个 new Foo().getName() 这里主要犹豫的时先执行Foo()还是new,因为此时new是带参数的,所以先new,=》(new Foo()).getName(),即调用的是Foo()上的getName(),因为在Foo()里没找到自己的getName(),所以去原型上找, 根据第一张图输出为 3
最后一个 new new Foo().getName()
由上面就可以知道带参数的new会优先执行故:
第一步:new(new Foo().getName())()
第二步:new((new Foo()).getName())()
先计算new Foo(), 在获取getName(),在对获取内容进行new ()计算,再进行调用;
也就是new( ( new Foo() ).getName())() =》new(Foo.prototype.getName)(),故输出为3
所以最终答案就是 2 4 1 1 2 3 3