一道超經(jīng)典js面試題Foo.getName()的故事
下面是一道超經(jīng)典的JS面試題。
蘊含了靜態(tài)屬性與實例屬性,變量提升,this指向,new一個函數(shù)的過程
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(); getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName(); new new Foo().getName();
輸出一下結(jié)果
Foo.getName(); //2 getName(); //4 Foo().getName(); //1 getName(); //1 new Foo.getName(); //2 new Foo().getName(); //3 new new Foo().getName(); //3
一、解析:
1.Foo.getName()
我們先看此題的上半部分做了什么,首先定義了一個叫Foo的函數(shù),之后為Foo創(chuàng)建了一個叫g(shù)etName的靜態(tài)屬性存儲了一個匿名函數(shù),之后為Foo的原型對象新創(chuàng)建了一個叫g(shù)etName的匿名函數(shù)。之后又通過函數(shù)變量表達式創(chuàng)建了一個getName的函數(shù),最后再聲明一個叫g(shù)etName函數(shù)。
第一問的 Foo.getName 自然是訪問Foo函數(shù)上存儲的靜態(tài)屬性,自然是2
二、解析:
2.getName()
為何輸出是4,這里考的是變量提升與函數(shù)聲明提升。我們知道使用var聲明變量會存在變量提升的情況,比如下面的例子中,即使在聲明前使用變量a也不會報錯,舉例:
console.log(a)// undefined var a = 1; console.log(a)// 1
因為聲明提前會讓聲明提升到代碼的最上層,而賦值操作停留在原地,所以上面代碼等同于:
var a console.log(a)// undefined a = 1; console.log(a)// 1
而函數(shù)聲明(注意是函數(shù)聲明,不是函數(shù)表達式或者構(gòu)造函數(shù)創(chuàng)建函數(shù))也會存在聲明提前的情況,即我們可以在函數(shù)聲明前調(diào)用函數(shù):
fn() // 1 function fn() { console.log(1); }; fn() // 1 //因為函數(shù)聲明提前,導(dǎo)致函數(shù)聲明也會被提到代碼頂端,所以等同于 function fn() { console.log(1); }; fn() // 1 fn() // 1
那這樣就存在一個問題了,變量聲明會提升,函數(shù)聲明也會提升,誰提升的更高呢?在你不知道的JavaScript中明確指出,函數(shù)聲明會被優(yōu)先提升,也就是說都是提升,但是函數(shù)比變量提升更高,所以題目中的兩個函數(shù)順序可以改寫成:
function getName() { console.log(5); }; var getName; getName = function () { console.log(4); };
這樣就解釋了為什么是輸出4。
三、解析:
3.Foo().getName()
其實可以看出來,我們在執(zhí)行Foo()函數(shù)的時候getName這個變量提升到外部的全局作用域中了,因為在js中,如果對于一個變量沒用用var 或者 let等聲明的話,他就默認(rèn)是全局屬性,就是window對象的一個屬性。所以在這里我們的全局的getName又被改了
因為我們Foo()執(zhí)行的時候返回了this而這里的this就是window對象 我們需要知道的是在瀏覽器中所有全局的聲明都是window對象的屬性和方法,所以這里我們調(diào)用this.getName()就會返回1了。
四、解析:
4.getName()
這里輸出1已經(jīng)毫無懸念,上一分析中,getName的值在Foo執(zhí)行時被修改了,所以再調(diào)用getName一樣等同于window.getName(),同樣是輸出1。
五、解析:
5.new Foo.getName()
首先還是先看運算符優(yōu)先級吧,我自個看完的結(jié)果是【new Foo() > Foo() > new Foo】,先運算方式2的Foo.getName() 結(jié)果為“2”,再new一個Foo實例對象,因此這里new的過程就相當(dāng)于單純把Foo.getName執(zhí)行了一遍輸出2。
六、解析:
6.new Foo().getName()
這里考了new基本概念,首先這個調(diào)用分為兩步,第一步new Foo()得到一個實例,第二步調(diào)用實例的getName方法。
我們知道new一個構(gòu)造函數(shù)的過程大致為,以構(gòu)造函數(shù)原型創(chuàng)建一個對象(繼承原型鏈),調(diào)用構(gòu)造函數(shù)并將this指向這個新建的對象,好讓對象繼承構(gòu)造函數(shù)中的構(gòu)造器屬性,如果構(gòu)造函數(shù)沒有手動返回一個對象,則返回這個新建的對象。
所以在執(zhí)行new Foo()時,先以Foo原型創(chuàng)建了一個對象,由于Foo.prototype上事先設(shè)置了一個getName方法(輸出3的那個),所以這個對象可通過原型訪問到這個方法,其次由于Foo內(nèi)部也沒提供什么構(gòu)造器屬性,最終返回了一個this(這個this指向?qū)嵗虼诉@里的this還是等同于我們前面概念提到的以Foo原型創(chuàng)建的對象,可以嘗試輸出這個實例,除了原型上有一個getName方法就沒有其它任何屬性,因此這里輸出3。
七、解析:
7.new new Foo().getName()
相當(dāng)于new(new Foo().getName())
先執(zhí)行new Foo().getName()由6部知道了輸出3,再創(chuàng)建Foo.prototype.getName()的實例返回。結(jié)果為3
總結(jié)
到此這篇關(guān)于js面試題Foo.getName()的文章就介紹到這了,更多相關(guān)js面試題Foo.getName()內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
原生javascript運動函數(shù)的封裝示例【勻速、拋物線、多屬性的運動等】
這篇文章主要介紹了原生javascript運動函數(shù)的封裝,結(jié)合實例形式分析了JavaScript封裝勻速、拋物線、多屬性的運動等函數(shù)及相關(guān)使用方法,需要的朋友可以參考下2020-02-02JavaScript數(shù)組去重的方法總結(jié)【12種方法,號稱史上最全】
這篇文章主要介紹了JavaScript數(shù)組去重的方法,結(jié)合實例形式較為詳細(xì)的總結(jié)分析了12種方法數(shù)組去重的方法,需要的朋友可以參考下2019-02-02改進 JavaScript 和 Rust 的互操作性并深入認(rèn)識 wasm-bindgen 組件
這篇文章主要介紹了改進 JavaScript 和 Rust 的互操作性并深入認(rèn)識 wasm-bindgen 組件,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-07-07微信小程序出現(xiàn)wx.navigateTo頁面不跳轉(zhuǎn)問題的解決方法
這篇文章主要介紹了微信小程序出現(xiàn)wx.navigateTo頁面不跳轉(zhuǎn)問題的解決方法,簡單分析了微信小程序出現(xiàn)wx.navigateTo頁面不跳轉(zhuǎn)情況的原因及相應(yīng)的解決方法,需要的朋友可以參考下2017-12-12javascript制作坦克大戰(zhàn)全紀(jì)錄(1)
本文寫作的目的是鞏固一下自己最近學(xué)習(xí)的js知識, 這個教程適合熟悉js基本語法和面向?qū)ο笳Z法的小伙伴學(xué)習(xí)。由于自己也是剛學(xué)js不久,所以難免出現(xiàn)錯誤。如果發(fā)現(xiàn)希望給予指正。2014-11-11JS實現(xiàn)獲取時間已經(jīng)時間與時間戳轉(zhuǎn)換
這篇文章主要為大家提供了用JavaScript編寫的獲取時間的類,以及時間戳轉(zhuǎn)時間的三種格式,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-03-03