一道JavaScript面試題:理解Function

2017.3.27更新
今天在刷題的時候,忽然發現以前已經有人在討論這道題了,並且還涉及到了運算符優先級的問題,這是本身一開始沒有想到的。(其實有人也說:程序寫多了,天然記住了什麼狀況下會發生什麼樣的事情,可是爲何會發生這樣的事情,可能問起來一時還真回答不了。我就屬於這種狀態,因此一開始並無考慮到運算符優先級的問題)。javascript

關於該問題的討論:java


今天看到的一道面試題,感受對理解JavaScript的Function以及原型鏈和閉包頗有幫助。本身並試着講述一下本身的理解,歡迎拍磚。函數

題目:

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 new Foo().getName();

請問上述代碼的輸出結果是什麼?this

2,4,1,1,2,3,3prototype

分析

  1. Foo.getName():函數調用輸出2很好理解,直接調用的Foo.getName();code

  2. getName():函數調用輸出爲4,這和變量提高有關係了,由於在函數調用分爲兩個步驟,第一進入上下文階段,第二爲執行階段。進入上下文時,會獲取arguments函數聲明變量聲明。只有在執行階段纔會進行變量賦值,而第四個是函數表達式,第五個爲函數聲明,因此他們等同於下面的形式:對象

    • 進入上下文階段:function getName(){alert(5);}

    • 執行階段(將以前的getName函數給覆蓋掉了):getName=function(){alert(4);}
      因此無論怎麼調用,答案中都應該不會出現5。

  3. Foo().getName()與第二次getName():第三個函數調用開始有迷惑性了。最後調用的getName函數,實際上是全局的getName。第二次調用就成了Foo()函數中的那個,由於其前面沒有var,也就是說這個getName並非一個私有變量,而是全局變量,因此將以前的全局中的getName函數在執行Foo()時會被覆蓋掉了。所以下一次再執行getName方法的結果就變成了1,而不是以前的4了。

    另外也跟new關鍵字有關,由於Foo()前沒有使用new,因此不會建立新的對象,並且 Foo的調用應該屬於函數調用,因此返回的this實際上是window對象,而不是Foo實 例(並無建立)。

  4. new Foo.getName():調用實際上是建立了一個Foo.getName的新的實例(函數自己也是Object),在建立對象的過程當中執行到了alert(2)語句,因此就輸出爲2;

  5. new Foo().getName():調用是先根據Foo.prototyoe建立一個Foo的實例,調用getName方法時,由於自身沒有getName方法,會去原型鏈上找,最後調用到Foo.prototype.getName,因此就是輸出爲3;

  6. new new Foo().getName():第七個就是第五和第六個的結合,先建立一個Foo實例,而後再建立Foo實例的getName函數(也就是Foo.prototype.getName)的實例。在建立的過程當中,執行到alert(3)語句,因此輸出3。

變化

經過修改Foo()函數體,能夠呈現出不一樣的調用變化。

  • Foo函數體內的getName前加上vargetName變成了私有變量),答案會變成:2,4,4,4,2,3,3

  • Foo函數體內的getName前加上thisgetName變成了屬性),答案會變成:2,4,1,1,2,1,1

相關文章
相關標籤/搜索