js经典面试题之Foo.getName

为什么会花一上午的时间来总结这道题呢?

原因是这样的:最近一直在准备面试的东西,也在B站学习(注意是学习!学习!学习!),看到尚硅谷分享的这道js面试题,当前学到了很多。

昨天晚上接到字节hr的电话,预约下周的一面面试。对于我这个菜鸟来讲,当然是得去牛客网刷刷面经辣(哭脸)

当当当当~~~~眼前一亮(这道题似曾相识啊!!!于是我翻手机相册翻到了截图(本人喜欢将一些知识点截图,蹲厕所的时候刷刷相册。哈哈哈,据说,上厕所时看知识最容易记住呢!)以下是证据(说话做事凭证据~)废话不多说,让我们一起愉快的学习吧。

题目如下:我又修改了以下,添加了两行代码

   function Foo() {
      getName = function () { alert(1); };
      return this;
    }
    Foo.getName = function () { alert(2); };
    Foo.prototype.getName = function () { alert(3); };
    var getName = function () { alert(4); };
    function getName() { alert(5); }
Foo.getName(); 
getName(); 
Foo().getName(); 
getName(); 
new Foo.getName()
new (Foo.getName)();
new Foo().getName();
(new Foo()).getName(); 

new new Foo().getName()

首先你要清楚,面试官考察的知识点(预解析,原型链,this)。面试官也是够狠的,区区十几行代码考察这么多知识点!

下面开始梳理解题过程:

预解析结果:(变量和函数声明提升,赋值不提升,再赋值前调用返回undefined,当变量和函数重名时,优先保留函数)

先预解析第一个函数:

  function Foo() {
      getName = function () { alert(1); };
      return this;
    }

 

碰到:

var getName = function () { alert(4); };   =》将getName声明提前,就剩下  getName = function(){alert(4)}
  function Foo() {
      getName = function () { alert(1); };
      return this;
    }
   var getName

碰到:

function getName() { alert(5); }
  function Foo() {
      getName = function () { alert(1); };
      return this;
    }
   var getName;
   function getName() { alert(5); 

以上就是预解析过程,接下来执行代码:

碰到

getName = function(){alert(4)},将预解析中的function getName() { alert(5); 重新赋值
此时代码为:
  function Foo() {
      getName = function () { alert(1); };
      return this;
    }
   var getName;
    Foo.getName = function () { alert(2); };
    Foo.prototype.getName = function () { alert(3); };
    getName = function () { alert(4); };

接下来,执行语句:

第一条语句:

Foo.getName(); 

找Foo函数找到getName方法    找到Foo.getName = function () { alert(2); }; 打印输出2

第二条语句:

getName();  

找到getName = function () { alert(4); }; 打印输出4

第三条语句:

Foo().getName();

首先明白一件事,运算符的优先级(点.的优先级高),但是因为()括号无法.点调用所以先将Foo函数执行完再去执行.getName()方法
等价于(Foo()).getName(); 先看Foo函数,一个全局变量getName,一个return this,
所以此时的getName再次被重新赋值
function Foo() {
      getName = function () { alert(1); };
      return this;
    }
   var getName;
    Foo.getName = function () { alert(2); };
    Foo.prototype.getName = function () { alert(3); };
    getName = function () { alert(1); };

Foo返回this,返回的就是调用Foo函数的对象那么是谁调用了Foo函数呢?很明显是window大哥,所以Foo函数的运行结果为window

所以(Foo()).getName() 等价于window,getName(),好了,你在全局找getName方法吧,getName = function () { alert(1); };,打印输出1

第四条语句:

getName():

等价于window.getName();这不就是和上一步一样吗,getName = function () { alert(1); };,打印输出1

第五条语句:

new Foo.getName()

还是那句话,点.的优先级高,先执行 那么就等价于 new(Foo.getName)(),问题来了,Foo.getName是什么呢?聪明的你应该已经发现了:
 Foo.getName = function () { alert(2); };
也就是说 new(Foo.getName)() = new ( function () { alert(2); };){} ,小二又向你无情的抛出了一个知识点:new函数调用时,会执行这个函数,所以打印输出2

第六条语句:

new (Foo.getName)();

你看她像不像第五题呢?,结果和第五条语句一样,输出结果为2

第七条语句:

 

new Foo().getName();

还是那句话:尽管.的优先级高,但()并不能.调用,所以会将new Foo()的值求出来再去.getName
 (new Foo()).getName()-->new关键字最后会生成一个实例对象foo.getName()
实例对象如何去找到对应的属性?(沿着隐式原型链__proto__,先去自身,再去__proto__,直到Object,直到都没有找到就返回undefined)
找到  Foo.prototype.getName = function () { alert(3); };  打印输出3

第八条语句:

(new Foo()).getName();

你看他像不像第七题呢?结果和第七条语句一样,输出3

第九条语句:

new new Foo().getName()

new ((new Foo()).getName)() => new (foo.getName)()
new (function () { alert(3); };)() ,直接执行new的函数,打印3
 
 
posted @ 2020-05-14 11:40  天空003  阅读(1506)  评论(0编辑  收藏  举报