判斷以下代碼的執行結果(涉及變數提升,函數聲明,原型鏈,this指向,作用域等知識點) "掘金" 上看到的一個筆試題目,記錄並分析總結以下考察點。 第一個 不用說什麼,直接調用Foo構造函數的getName屬性,輸出2。 第二個 調用當前作用域下的getName函數,要註意 函數表達式 和 函數聲明 ...
判斷以下代碼的執行結果(涉及變數提升,函數聲明,原型鏈,this指向,作用域等知識點)
掘金 上看到的一個筆試題目,記錄並分析總結以下考察點。
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(); // 2
getName(); // 4
Foo().getName(); // 1
getName(); // 1
new Foo.getName(); // 2
new Foo().getName(); // 3
new new Foo().getName(); //3
第一個 不用說什麼,直接調用Foo構造函數的getName屬性,輸出2。
第二個 調用當前作用域下的getName函數,要註意函數表達式和函數聲明的不同:
- 函數聲明會‘被提前’到外部腳本或者外部函數的頂部,所以這種方式聲明的函數,可以在它被定義之前的代碼中所調用。
- 函數表達式,就和聲明變數一樣了,變數聲明會提前到頂部,但是賦值會在執行到原位置的時候才進行。
4會變數提升,但是並沒有賦值,然後5函數提升(在4賦值之前調用下getName(),輸出的是5),而代碼執行4的位置時,會賦值就覆蓋了5。所以第二個會輸出4。
第三個 Foo()執行時,Foo函數體內並沒有getName變數,所以就去上一層window下找,重新賦值了window下的getName為輸出1(如果沒有找到,會在window下創建一個getName),然後返回了this,這裡的this指向的是window,再調用window的getName屬性,即為重新賦值後的輸出1。
第四個 執行當前作用域下的getName,註意此時getName已經重新賦值,所以輸出1
第五個 這裡需要特別註意表達式的執行順序,詳見 MDN
.
比無參數列表new
執行的優先順序高,所以是 new (Foo.getName)()
輸出2
第六個 同樣是執行順序
()
比.
的執行優先順序高,所以是 (new Foo()).getName()
,Foo作為構造函數,指定了返回this,而在構造函數中,this指向的是生成的實例,而Foo中沒有對實例添加getName屬性,所以在調用實例的getName時,會去Foo.prototype中找,所以輸出3
第七個 同樣是執行順序
new ((new Foo()).getName)()
是以原型鏈上的getName為構造函數來執行,輸出3