2017.3.27更新
今天在刷題的時候,忽然發現以前已經有人在討論這道題了,並且還涉及到了運算符優先級的問題,這是本身一開始沒有想到的。(其實有人也說:程序寫多了,天然記住了什麼狀況下會發生什麼樣的事情,可是爲何會發生這樣的事情,可能問起來一時還真回答不了
。我就屬於這種狀態,因此一開始並無考慮到運算符優先級的問題)。javascript
關於該問題的討論:java
https://segmentfault.com/a/11...segmentfault
今天看到的一道面試題,感受對理解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
Foo.getName()
:函數調用輸出2很好理解,直接調用的Foo.getName()
;code
getName()
:函數調用輸出爲4,這和變量提高有關係了,由於在函數調用分爲兩個步驟,第一進入上下文階段,第二爲執行階段。進入上下文時,會獲取arguments
,函數聲明
,變量聲明
。只有在執行階段纔會進行變量賦值,而第四個是函數表達式,第五個爲函數聲明,因此他們等同於下面的形式:對象
進入上下文階段:function getName(){alert(5);}
執行階段(將以前的getName函數給覆蓋掉了):getName=function(){alert(4);}
因此無論怎麼調用,答案中都應該不會出現5。
Foo().getName()
與第二次getName()
:第三個函數調用開始有迷惑性了。最後調用的getName
函數,實際上是全局的getName
。第二次調用就成了Foo()
函數中的那個,由於其前面沒有var
,也就是說這個getName
並非一個私有變量,而是全局變量,因此將以前的全局中的getName
函數在執行Foo()
時會被覆蓋掉了。所以下一次再執行getName
方法的結果就變成了1
,而不是以前的4
了。
另外也跟new
關鍵字有關,由於Foo()
前沒有使用new
,因此不會建立新的對象,並且 Foo
的調用應該屬於函數調用,因此返回的this
實際上是window
對象,而不是Foo
實 例(並無建立)。
new Foo.getName()
:調用實際上是建立了一個Foo.getName
的新的實例(函數自己也是Object),在建立對象的過程當中執行到了alert(2)
語句,因此就輸出爲2;
new Foo().getName()
:調用是先根據Foo.prototyoe
建立一個Foo
的實例,調用getName
方法時,由於自身沒有getName
方法,會去原型鏈上找,最後調用到Foo.prototype.getName
,因此就是輸出爲3;
new new Foo().getName()
:第七個就是第五和第六個的結合,先建立一個Foo
實例,而後再建立Foo
實例的getName
函數(也就是Foo.prototype.getName
)的實例。在建立的過程當中,執行到alert(3)
語句,因此輸出3。
經過修改Foo()函數體,能夠呈現出不一樣的調用變化。
Foo函數體內的getName
前加上var
(getName
變成了私有變量),答案會變成:2,4,4,4,2,3,3
。
Foo函數體內的getName
前加上this
(getName
變成了屬性),答案會變成:2,4,1,1,2,1,1
。