嘗試解析js面試題(一)

說明:這是一道比較典型的綜合考察js中作用域、this指向、對象、解析順序運算符優(yōu)先級等概念的綜合性考題;話不多說,先上題;

原作者解析:小小滄海(博客園)

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();

解析:

1、Foo.getName(); //2

1)結(jié)果執(zhí)行的是Foo對象的一個叫做getName()的屬性,而1、4、5中的getName都是作為函數(shù)存在,所以可以排除1、4、5

2)剩下兩個中,2是Foo對象自身的屬性,3是Foo對象原型鏈上的屬性,而自身屬性的優(yōu)先級高于原型鏈上的屬性,所以執(zhí)行結(jié)果是2

2、getName(); //4

1)結(jié)果執(zhí)行的是getName函數(shù),而題目代碼中有3個相關(guān)函數(shù),分別是1、4、5

2)1中的getName是定義在Foo函數(shù)中的函數(shù),由于Foo尚未執(zhí)行,因此它沒有暴露出來,無法被外部調(diào)用,可以排除

3)4和5都可以被正常調(diào)用,關(guān)鍵在調(diào)用先后問題

4)由于5是普通函數(shù)(優(yōu)先級最高),4是匿名函數(shù);js解析時會將5提前至最上方優(yōu)先解析,而后面解析的4會將5覆蓋,所以執(zhí)行結(jié)果是4

3、Foo().getName(); //1

1)結(jié)果執(zhí)行的是Foo函數(shù),F(xiàn)oo函數(shù)中有個返回值是this;this被普通函數(shù)調(diào)用后,指向的對象一定是window對象,所以此處的結(jié)果已經(jīng)可以解析為window.getName(),即調(diào)用getName()函數(shù)

2)由于window.getName()已經(jīng)被修改為1,所以執(zhí)行結(jié)果是1(??)

上面那句話是原作者的解釋,此處還沒理解透徹為什么1沒有被2覆蓋;下面舉個例子對比下:

//第一個例子是題目的類型,不明為何上邊f(xié)n1的結(jié)果未被覆蓋??
function fn1 (){
    a = 1;
    return this
}
fn1()
var a = 2
console.log(fn1().a) //1

//第二個例子是我理解的會正常出現(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ōu)先級的問題,就題目所需來看,成員訪問".">new(帶參數(shù))>函數(shù)調(diào)用"()"(注意,"()"分為函數(shù)調(diào)用及優(yōu)先運算兩種,優(yōu)先級是不同的;原作者開始的解釋就出現(xiàn)了錯誤)

2)結(jié)果先執(zhí)行Foo.getName(),結(jié)果同第一題為2;而new 2不會有任何變化,因此這里的結(jié)果也是2

6、new Foo().getName(); //3

1)從結(jié)果來看,應(yīng)該理解成(new Foo()).getName()這樣執(zhí)行

2)根據(jù)成員訪問".">new(帶參數(shù))>函數(shù)調(diào)用"()";成員訪問優(yōu)先執(zhí)行,右側(cè)是.getName()沒問題

3)左側(cè)分為兩種可能:一種是new(帶參數(shù)),即(new Foo());此處結(jié)果是構(gòu)建一個函數(shù)

4)另一種是先執(zhí)行Foo()函數(shù)后再將其結(jié)果new

5)因為new(帶參數(shù))>函數(shù)調(diào)用"()",所以是執(zhí)行的(new Foo()),此對象Foo()自身沒有g(shù)etName這個屬性,所以會向上追溯其原型鏈上的屬性,即在此處執(zhí)行了3;因此結(jié)果是3

//這里就是模擬new Foo()的結(jié)果
function F(){return this}
new F() //F {}

關(guān)于這點,原作者有解釋如下(還是可以理解的):

構(gòu)造函數(shù)的返回值

在傳統(tǒng)語言中,構(gòu)造函數(shù)不應(yīng)該有返回值,實際執(zhí)行的返回值就是此構(gòu)造函數(shù)的實例化對象。

而在js中構(gòu)造函數(shù)可以有返回值也可以沒有。

1、沒有返回值則按照其他語言一樣返回實例化對象。

2、若有返回值則檢查其返回值是否為引用類型。如果是非引用類型,如基本類型(string,number,boolean,null,undefined)則與無返回值相同,實際返回其實例化對象。

3、若返回值是引用類型,則實際返回值為這個引用類型。

原題中,返回的是this,而this在構(gòu)造函數(shù)中本來就代表當(dāng)前實例化對象,遂最終Foo函數(shù)返回實例化對象。

7、new new Foo().getName(); //3

1)這題我其實是懵逼的(懵逼臉??)

2)求高手指教了 _ (:з」∠)_

還是貼下原作者解釋,感覺有點不對

第七問, new new Foo().getName(); 同樣是運算符優(yōu)先級問題。

最終實際執(zhí)行為:

new ((new Foo()).getName)();

先初始化Foo的實例化對象,然后將其原型上的getName函數(shù)作為構(gòu)造函數(shù)再次new。

遂最終結(jié)果為3


最后,引用一張原作者提供的相當(dāng)實用的運算符優(yōu)先級表格(鼓掌)

運算符優(yōu)先級--博客園
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,502評論 19 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,623評論 18 399
  • 最近在網(wǎng)上看了一道有關(guān)前端的面試題感覺很不錯,就在這里分享給大家。 題目: function Foo() { g...
    穿越人海遇見你閱讀 1,035評論 0 12
  • Github原文 題目 這幾天面試上幾次碰上這道經(jīng)典的題目,特地從頭到尾來分析一次答案,這道題的經(jīng)典之處在于它綜合...
    秋風(fēng)喵閱讀 948評論 0 19
  • 題目如下: 答案是: 此題涉及的知識點眾多,包括變量定義提升、this指針指向、運算符優(yōu)先級、原型、繼承、全局變量...
    WEB攻程獅閱讀 1,041評論 4 39

友情鏈接更多精彩內(nèi)容