說(shuō)明:這是一道比較典型的綜合考察js中作用域
、this指向
刀崖、對(duì)象
惊科、解析順序
、運(yùn)算符優(yōu)先級(jí)
等概念的綜合性考題亮钦;話不多說(shuō)馆截,先上題;
原作者解析:小小滄海(博客園)
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);
}
//請(qǐng)寫(xiě)出以下輸出結(jié)果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
解析:
1、Foo.getName(); //2
1)結(jié)果執(zhí)行的是Foo對(duì)象的一個(gè)叫做getName()的屬性蜡娶,而1混卵、4、5中的getName都是作為函數(shù)存在窖张,所以可以排除1幕随、4、5
2)剩下兩個(gè)中宿接,2是Foo對(duì)象自身的屬性合陵,3是Foo對(duì)象原型鏈上的屬性,而自身屬性的優(yōu)先級(jí)高于原型鏈上的屬性澄阳,所以執(zhí)行結(jié)果是2
2拥知、getName(); //4
1)結(jié)果執(zhí)行的是getName函數(shù),而題目代碼中有3個(gè)相關(guān)函數(shù)碎赢,分別是1低剔、4、5
2)1中的getName是定義在Foo函數(shù)中的函數(shù)肮塞,由于Foo尚未執(zhí)行襟齿,因此它沒(méi)有暴露出來(lái),無(wú)法被外部調(diào)用枕赵,可以排除
3)4和5都可以被正常調(diào)用猜欺,關(guān)鍵在調(diào)用先后問(wèn)題
4)由于5是普通函數(shù)(優(yōu)先級(jí)最高),4是匿名函數(shù)拷窜;js解析時(shí)會(huì)將5提前至最上方優(yōu)先解析开皿,而后面解析的4會(huì)將5覆蓋,所以執(zhí)行結(jié)果是4
3篮昧、Foo().getName(); //1
1)結(jié)果執(zhí)行的是Foo函數(shù)赋荆,F(xiàn)oo函數(shù)中有個(gè)返回值是this;this被普通函數(shù)調(diào)用后懊昨,指向的對(duì)象一定是window對(duì)象窄潭,所以此處的結(jié)果已經(jīng)可以解析為window.getName(),即調(diào)用getName()函數(shù)
2)由于window.getName()已經(jīng)被修改為1酵颁,所以執(zhí)行結(jié)果是1(嫉你??)
上面那句話是原作者的解釋躏惋,此處還沒(méi)理解透徹為什么1沒(méi)有被2覆蓋幽污;下面舉個(gè)例子對(duì)比下:
//第一個(gè)例子是題目的類型,不明為何上邊f(xié)n1的結(jié)果未被覆蓋其掂?油挥?
function fn1 (){
a = 1;
return this
}
fn1()
var a = 2
console.log(fn1().a) //1
//第二個(gè)例子是我理解的會(huì)正常出現(xiàn)覆蓋的情況
function fn1 (){
a = 1;
}
fn1()
var a = 2
console.log(a) //2
4潦蝇、getName(); //1
1)執(zhí)行g(shù)etName即是執(zhí)行window.getName款熬;所以執(zhí)行結(jié)果同上題是1
5深寥、new Foo.getName(); //2
1)此處考察到了運(yùn)算符優(yōu)先級(jí)的問(wèn)題,就題目所需來(lái)看贤牛,成員訪問(wèn)".">new(帶參數(shù))>函數(shù)調(diào)用"()"
(注意惋鹅,"()"分為函數(shù)調(diào)用及優(yōu)先運(yùn)算兩種,優(yōu)先級(jí)是不同的殉簸;原作者開(kāi)始的解釋就出現(xiàn)了錯(cuò)誤)
2)結(jié)果先執(zhí)行Foo.getName()闰集,結(jié)果同第一題為2;而new 2不會(huì)有任何變化般卑,因此這里的結(jié)果也是2
6武鲁、new Foo().getName(); //3
1)從結(jié)果來(lái)看,應(yīng)該理解成(new Foo()).getName()
這樣執(zhí)行
2)根據(jù)成員訪問(wèn)".">new(帶參數(shù))>函數(shù)調(diào)用"()"
蝠检;成員訪問(wèn)優(yōu)先執(zhí)行沐鼠,右側(cè)是.getName()沒(méi)問(wèn)題
3)左側(cè)分為兩種可能:一種是new(帶參數(shù)),即(new Foo())
叹谁;此處結(jié)果是構(gòu)建一個(gè)函數(shù)
4)另一種是先執(zhí)行Foo()
函數(shù)后再將其結(jié)果new
饲梭;
5)因?yàn)閚ew(帶參數(shù))>函數(shù)調(diào)用"()",所以是執(zhí)行的(new Foo())
焰檩,此對(duì)象Foo()自身沒(méi)有g(shù)etName這個(gè)屬性憔涉,所以會(huì)向上追溯其原型鏈上的屬性,即在此處執(zhí)行了3析苫;因此結(jié)果是3
//這里就是模擬new Foo()的結(jié)果
function F(){return this}
new F() //F {}
關(guān)于這點(diǎn)兜叨,原作者有解釋如下(還是可以理解的):
構(gòu)造函數(shù)的返回值
在傳統(tǒng)語(yǔ)言中,構(gòu)造函數(shù)不應(yīng)該有返回值衩侥,實(shí)際執(zhí)行的返回值就是此構(gòu)造函數(shù)的實(shí)例化對(duì)象浪腐。
而在js中構(gòu)造函數(shù)可以有返回值也可以沒(méi)有。
1顿乒、沒(méi)有返回值則按照其他語(yǔ)言一樣返回實(shí)例化對(duì)象议街。
2、若有返回值則檢查其返回值是否為引用類型璧榄。如果是非引用類型特漩,如基本類型(string,number,boolean,null,undefined)則與無(wú)返回值相同,實(shí)際返回其實(shí)例化對(duì)象骨杂。
3涂身、若返回值是引用類型,則實(shí)際返回值為這個(gè)引用類型搓蚪。
原題中蛤售,返回的是this,而this在構(gòu)造函數(shù)中本來(lái)就代表當(dāng)前實(shí)例化對(duì)象,遂最終Foo函數(shù)返回實(shí)例化對(duì)象悴能。
7揣钦、new new Foo().getName(); //3
1)這題我其實(shí)是懵逼的(懵逼臉??)
2)求高手指教了 _ (:з」∠)_
還是貼下原作者解釋,感覺(jué)有點(diǎn)不對(duì)
第七問(wèn), new new Foo().getName(); 同樣是運(yùn)算符優(yōu)先級(jí)問(wèn)題漠酿。
最終實(shí)際執(zhí)行為:
new ((new Foo()).getName)();
先初始化Foo的實(shí)例化對(duì)象冯凹,然后將其原型上的getName函數(shù)作為構(gòu)造函數(shù)再次new。
遂最終結(jié)果為3