天天看點

Faicso函數問題——JS作用域,原型鍊,變量提升Faicso函數問題——JS作用域,原型鍊,變量提升

Faicso函數問題——JS作用域,原型鍊,變量提升

今天偶然在一個web前端交流群中看到了一道群友分享的JavaScript面試題,感覺有點意思,在此分享下。

本文僅個人觀點,歡迎各位前輩或者小夥伴批評指正錯誤,十分感謝!!

題目:

function Faicso() {
      getName = function () { console.log('圖檔') }
      return this
    }
    Faicso.getName = function () { console.log('微傳單')}
    Faicso.prototype.getName = function () {console.log('建站')}
    var getName = function () {console.log('互動')}
    function getName() {console.log('商城')}
    // 說說下面的輸出情況
	Faicso.getName()
	getName()
	Faicso().getName()
	getName() 
	new Faicso.getName() 
	new Faicso().getName()
	new new Faicso().getName()
           

這道題的執行順序很有講究,若是将這七個執行順序調換一下,結果很可能會不同。

輸出結果:

Faicso.getName()//微傳單                
    getName()// 互動                        
    Faicso().getName() // 圖檔              相當于 window.getName()  但是若是在這裡寫成 window.getName()或 this.getName() 将傳回 '互動'的getName函數
    getName() // 圖檔
    new Faicso.getName() // 微傳單
    new Faicso().getName()// 建站
    new new Faicso().getName() // 建站

           

答案步步詳解

Faicso.getName()
	// 微傳單  見題目第五行代碼,為Faicso函數添加getName()方法(在JS中函數也是對象,對象則有屬性和方法)  
	// 但這裡為Faicso函數直接添加的方法隻能為其本身使用,不能被 new Faicso() 執行個體對象使用
	// 要想執行個體對象也能使用 getName()方法的話,需在 Faicso.prototype 上添加此方法(本題有涉及到)      
    getName()
    // 互動  這裡為什麼會是'互動',而不是'商城'或'圖檔'呢?
    // 這裡的原因涉及到 變量提升 ,參看下文片段解釋1                      
    Faicso().getName() // 圖檔    
    // 相當于 window.getName() 
    // 但是若是在這裡寫成 window.getName()或 this.getName() 将傳回 '互動'的getName函數
    // 因為這裡首先調用 執行了Faicso函數,Faicso函數内部又對全局的getName方法重新指派為'圖檔'的函數
    getName() // 圖檔
    // 因為上一步執行了Faicso函數,為this.getName方法重新指派為'圖檔'的函數,是以這裡再次調用全局的getName方法就會輸出'圖檔'
    new Faicso.getName() // 微傳單
    // 這裡new 了一個 Faicso.getName()函數的執行個體對象,輸出同調用 Faicso.getName()
    new Faicso().getName()// 建站
    // 這裡就涉及到了上面提到的 new Faicso()執行個體調用getName()方法
    new new Faicso().getName() // 建站
    // 這裡是 建立了一個 Faicso()執行個體的getName()方法的執行個體對象
    // 而 Faicso()執行個體的getName()方法 同上都是繼承于Faicso.prototype
           

片段解釋

片段1. getName() // 互動 這裡為什麼會是’互動’,而不是’商城’或’圖檔’呢?

// 這裡的原因涉及到 變量提升

// 原題目代碼
var getName = function () {console.log('互動')}
    function getName() {console.log('商城')}
    
// 相當于 變量提升後的代碼
function getName(){console.log('商城')}  // 函數聲明提升 (函數聲明提升優先于變量聲明的提升)
var getName  // 變量聲明提升,但指派未提升
getName = function (){console.log('互動')} // 變量聲明提升,但指派未提升
           

是以最終 ’ 互動’ 的函數覆寫了 ‘商城’ 的函數。

繼續閱讀