題目如下:
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);}
//請寫出以下輸出結(jié)果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
首先分析一下題目
getName分別以變量,和函數(shù)變量的形式聲明肿仑,涉及到變量聲明提升致盟。因此實際執(zhí)行是
function Foo() {
getName = function () { alert (1); };
return this;
}
var getName;//只提升變量聲明
function getName() { alert (5);}//覆蓋var的聲明
Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
getName = function () { alert (4);};
第一問
Foo.getName(); 自然是訪問Foo函數(shù)上存儲的靜態(tài)屬性//2
第二問
getName();也可由以上分析易得4;
第三問
Foo().getName();先執(zhí)行Foo()函數(shù),然后調(diào)用Foo函數(shù)的返回值對象的getName屬性函數(shù)尤慰。
執(zhí)行Foo()函數(shù)返回this,這里是window馏锡,也就等于window.getName();然后Foo()執(zhí)行過程中g(shù)etName沒有var聲明,是全局變量伟端,因此也就修改了先前的getName函數(shù)杯道,此時代碼可認為是
function Foo() {
getName = function () { alert (1); };
return this;
}
var getName;//只提升變量聲明
function getName() { alert (5);}//覆蓋var的聲明
Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
getName=function(){alert(1);}//覆蓋上文getName定義
所以輸出1;
第四問
getName();和上一問一樣,直接輸出1;
第五問
new Foo.getName();后面幾問考察到j(luò)s運算符優(yōu)先級。
詳細優(yōu)先級匯總表點擊這里
上圖優(yōu)先級從高到低排列;.優(yōu)先級高于new,這里的new我認為是無參的荔泳,因此優(yōu)先級最低蕉饼。
所以是new ((Foo.getName)())
也就是把Foo.getName()函數(shù)作為了構(gòu)造函數(shù)來執(zhí)行。
第六問
new Foo().getName()
//?此時的點不是成員訪問運算了么玛歌,作者說等于(new Foo()).getName()
先執(zhí)行new Foo()
構(gòu)造函數(shù)的返回值
分三種情況:
- 沒有返回值昧港,返回實例化對象。
function Foo(){};
>undefined;
new Foo()
>Foo {}
- 若有返回值檢查其返回值是否為引用類型支子。如果是非引用類型创肥,如基本類型(string、number、boolean叹侄、null巩搏、undefind)則與無返回值相同,返回實例化對象趾代。
function Fn(){return true}
>undefined
new Fn()
>Fn {}
- 若返回值是引用類型贯底,則實際返回值為這個引用類型。
function fn(){return {a:1}}
>undefined
new fn()
>Object {a: 1}
this不能當做引用類型
回到題目撒强,new Foo().getName() 禽捆,原題中返回this,代表當前實例化對象,然后調(diào)用實例化對象的getName(),//3
第七問
new new Foo().getName();
最終等于new ((new Foo()).getName)();
//這里的順序也是一個問題
先初始化Foo的實例化對象,將其原型上的getName作為構(gòu)造函數(shù)再次new飘哨,還是3.
總結(jié)
對于后面幾個問題來說胚想,與其用優(yōu)先級的知識來解釋,還不如用(new 構(gòu)造函數(shù))更加通俗易懂芽隆。譬如 new Foo(),返回Foo函數(shù)的一個實例Foo{},然后總不能再new一個實例吧浊服,所以只能等后邊再結(jié)合成一個函數(shù),就像第五問 new Foo.getName() ,Foo只是個函數(shù)名,而Foo.getName()是個函數(shù)胚吁。第六問new Foo().getName(),Foo()是一個函數(shù)牙躺,就直接new 了,然后返回Foo的實例Foo{},再找繼承的getName()囤采;第七問new new Foo().getName(),(new Foo())返回實例述呐,所以再和后面的結(jié)合成一個函數(shù),然后再new蕉毯。不知道這樣理解有多少問題,還請各位賜教~