題目以下:node
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()
// 輸出結果爲
// 2
// 4
// 1
// 1
// 2
// 3
// 3
複製代碼
下面對輸出值進行分析:函數
Foo.getName()
輸出爲 2, 訪問的是函數 Foo 上的靜態屬性,輸出爲 2。優化
如今,嘗試在函數內定義 getName 函數和在 Foo 原型上綁定 getName 函數, 都沒法成功執行 Foo.getName()
, 而以字面量建立對象的方式建立對象後,則能正常的執行 getName()
函數。ui
經過建立對象運行 getName()
定義在函數內部沒法正常執行,即便它是全局變量。this
結論: 因爲函數自己是對象,經過函數綁定屬性和方法屬於靜態方法 ,能夠直接調用。綁定在原型上的屬性和方法要建立對象後才能調用,在構造函數對象內部定義的方法沒法經過對象調用。spa
getName();
結果輸出爲 4,而不是輸出 5。這是由於JS 存在變量聲明提高(全部聲明的變量或聲明的函數都會被提高到當前函數的頂部)。prototype
故代碼執行順序爲:code
var getName;
function getName() { alert(5); }
// ... 省略代碼
getName = function () { alert(4) }
複製代碼
最終執行 getName
輸出爲 4cdn
延伸題目:對象
console.log( Foo )
function Foo() {
console.log(1);
}
var Foo = 1
複製代碼
Foo 的輸出結果爲?
Foo().getName();
輸出值爲1, 先執行 Foo() 函數,定義全局變量 getName, 以後調用全局對象的 getName()
方法, 返回 1。
注意, Foo()
函數返回的 this
指向的是全局對象 window,因此調用的是全局對象 getName()
。 函數裏的 getName 綁定的是全局對象,經過 Foo 調用會報錯。
Node 下執行這條語句會報錯,由於 node 沒有全局對象 window, 因此沒法調用 getName
getName()
調用全局函數, 由於執行 Foo()
, 更新了 getName 的值,因此返回 1。
new Foo.getName()
考察了運算符的優先級。 .
的優先級高於 new, 至關於執行 new (Foo.getName)()
, 至關於執行 getName 的構造函數,返回 2
new Foo().getName()
執行方式爲 (new Foo()).getName()
先生成 Foo 對象, 再執行 getName()
函數。 在 new Foo()
返回的是新建立的空對象,因爲對象這時還沒綁定屬性 getName, 因此這時調用的是原型上的 getName, 結果返回3
注意: 構造函數
return this
,在執行 new 的時候,返回的是新建立的對象。
延伸題目:
function A() {
this.a = 2;
function B() {
this.a = 1;
}
return B();
}
console.log(new A());
複製代碼
a的值是? 若是 return new B();
a的值是?
new new Foo().getName()
能夠改寫爲 new ((new Foo()).getName)()
先初始化實例,而後將原型對象上的 getName() 做爲構造函數執行,結果返回 3
最終代碼能夠優化爲
var getName;
function getName() { alert(5); }
function Foo() {
getName = function() { alert(1); }
return this
}
Foo.getName = function() { alert(2); }
Foo.prototype.getName = function() { alert(3); }
getName = function () { alert(4); }
Foo.getName(); // 2
getName(); // 4
Foo();
getName(); // 1
getName(); // 1
Foo.getName(); // 2
(new Foo()).getName(); // 3
(new Foo()).getName(); // 3
複製代碼