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
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM