記Javascript一道題的理解

小龍女先生發表於2017-05-02

程式碼如下:

function Foo(){
    getName = function(){ console.log("1"); }
    return this;
}
Foo.getName = function(){
    console.log("2");
}
Foo.prototype.getName = function(){
    console.log("3");
}
var getName = function(){
    console.log("4");
}
function getName(){
    console.log("5");
}
Foo.getName(); //2
getName(); //4
Foo().getName(); //1
getName(); //1
new Foo.getName(); //2 => new (Foo.getName)() new無引數列表
new Foo().getName(); // 3 => (new Foo()).getName(); //new有引數列表
new new Foo().getName(); //3 => new ((new Foo()).getName)() //new有引數列表

Foo.getName()

輸出結果為:2
原理:他呼叫的是Foo的靜態方法(如果C#、java等後端語言來說),其實是因為Javascript中的Function本身就是Function和Object的結合,所以function既是函式,也是物件。在這裡Foo就是執行了他物件上的一個function而已。

getName()

輸出結果為:4
原理:可能你會想為什麼不是5,function變數會提升到作用域的頂部,而var定義的則不會,所以var宣告的覆蓋掉function宣告。所以結果為4

Foo().getName()

輸出結果為:1
原理:Foo()是函式呼叫,Foo執行體中對getName進行了重新賦值(全域性的getName,根據作用域鏈向上查詢),返回的this為window(Foo執行時沒有呼叫,預設為全域性),然後.getName()呼叫了全域性的getName(也就是被Foo執行體重寫的getName),所以結果為:1

getName()

輸出結果為:1 原理:因為Foo執行體中對全域性getName重寫了,這時呼叫的又是全域性的getName。所以結果為:1

new Foo.getName()

輸出結果為:2
原理:

  • 由於new無參,與new有參的運算優化級一樣。new有參的與.運算子同一級別,而new無參的低一個級別。所以會先執行.運算子選擇到Foo的靜態方法getName
  • 然後執行new,獲得的是Foo.getName的一個例項。所以輸出結果為:2

new Foo().getName()

輸出結果為:3

原理:

  • 由於new是有參的,與.運算子同級,按照從左向右的執行順序,先執行new Foo()。
  • new Foo()是需要值得我們的注意,因為他有一個返回值。存在返回值分為兩種情況:
    • 無返回與返回為基本型別是一樣的效果:返回都是例項物件(也就是當前的this)
    • 返回為引用型別:返回的為這個引用型別的物件,此時例項物件被替換了(也就是當前的this沒有返回)。因數new Foo()返回是例項物件
  • .getName():選擇是上一步例項的此方法,所以輸出結果為:3

new new Foo().getName()

輸出結果為:3
原理:主要是運算子優先順序的考查,例項開發中應該不會這樣直接的用到。首先new有參,然後.getName(.運算子)(為什麼是.運算子,這是因為new無參級別低一個檔次),再則new有參。

相關文章