一道前端面试题引发的思考

211 阅读2分钟

最近刷题遇到一个经典的 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