一道JS前端閉包面試題解析
問(wèn)題
代碼A
function fun(n,o){ console.log(o); return { fun:function(m){//[2] return fun(m,n);//[1] } } } var a=fun(0); a.fun(1); a.fun(2); a.fun(3); var b=fun(0).fun(1).fun(2).fun(3); var c=fun(0).fun(1); c.fun(2); c.fun(3);
求出程序輸出
這是一個(gè)閉包測(cè)試題
轉(zhuǎn)換為等價(jià)代碼
return返回的對(duì)象的fun屬性對(duì)應(yīng)一個(gè)新建的函數(shù)對(duì)象,這個(gè)函數(shù)對(duì)象將形成一個(gè)閉包作用域,使其能夠訪問(wèn)外層函數(shù)的變量n及外層函數(shù)fun,為了不將fun函數(shù)和fun屬性搞混,我們將上述代碼修改如下:
代碼B
function _fun_(n,o){ console.log(o); return { fun:function(m){ return _fun_(m,n); } } } var a=_fun_(0);//undefined a.fun(1);//0 a.fun(2);//0 a.fun(3);//0 var b=_fun_(0).fun(1).fun(2).fun(3); //undefined,0,1,2 var c=fun(0).fun(1);//undefined,0, c.fun(2);//1 c.fun(3); //1
那么就有同學(xué)問(wèn)了,為什么可以這樣改呢,你怎么能確定[1]處的fun不是[2]代碼所在處的fun呢,要知道此處的fun屬性可是指向一個(gè)函數(shù)對(duì)象哦~
這里就要說(shuō)到JS的詞法作用域,JS變量作用域存在于函數(shù)體中即函數(shù)體,并且變量的作用域是在函數(shù)定義聲明的時(shí)候就是確定的,而非在函數(shù)運(yùn)行時(shí)。
如下代碼
var name="global"; function foo(){ console.log(name); } function fooOuter1(){ var name="local"; foo(); } fooOuter1();//輸出global 而不是local,并且和閉包沒(méi)有任何關(guān)系 function fooOuter2(){ var name="local"; function foo(){ console.log(name); } foo(); } fooOuter2();//輸出local 而不是global,在函數(shù)聲明是name變量作用域就在其外層函數(shù)中,嗯嗯就是閉包~
好了我們回到題目,在函數(shù)聲明定義階段,[2]處的匿名函數(shù)進(jìn)行定義聲明,發(fā)現(xiàn)在[1]處需要引用一個(gè)名為fun的函數(shù)對(duì)象,那么首先在當(dāng)前函數(shù)體內(nèi)尋找,發(fā)現(xiàn)沒(méi)有,那么就到其外層函數(shù)-這個(gè)匿名函數(shù)的包裹函數(shù)中去查找,發(fā)現(xiàn)也沒(méi)有,到外層函數(shù)中去,發(fā)現(xiàn)外面沒(méi)有函數(shù)包裹了,那就到全局環(huán)境下去找,額偶終于找到了......就把fun函數(shù)指定為全局環(huán)境下的fun函數(shù)對(duì)象并加入到匿名函數(shù)的閉包中去。至此我們就知道代碼B為什么和代碼A是等價(jià)的了~~~
創(chuàng)建閉包作用域
JS在詞法分析結(jié)束后,確定了1個(gè)閉包,就是返回的對(duì)象fun屬性對(duì)應(yīng)的匿名函數(shù)的閉包-訪問(wèn)全局環(huán)境下的_func_及其外層函數(shù)的函數(shù)內(nèi)部變量n;
在每次_func_執(zhí)行的時(shí)候,都會(huì)將閉包中變量的作用域信息傳遞到函數(shù)執(zhí)行環(huán)境中,供函數(shù)執(zhí)行時(shí)獲取變量值時(shí)使用
執(zhí)行輸出
var a=_fun_(0);//undefined a.fun(1);//0 a.fun(2);//0 a.fun(3);//0
_fun_函數(shù)執(zhí)行,因?yàn)榈?個(gè)參數(shù)未定義,輸出undefined。然后返回一個(gè)對(duì)象,帶有fun屬性,指向一個(gè)函數(shù)對(duì)象-帶有閉包,能夠訪問(wèn)到_fun_和變量n_
a.fun(1)執(zhí)行返回的對(duì)象的fun方法,傳入m的值1,調(diào)用返回_fun_(1,0)
所以輸出為0,a.fun(2),a.fun(3)和a.fun(1)
var b=_fun_(0).fun(1).fun(2).fun(3);
等價(jià)代碼:
var b=_fun_(0);
var b1=b.fun(1);
var b2=b1.fun(2);//[3]
var b3=b2.fun(3);//[4]
前2句和上面的輸出相同undefined,0,當(dāng)[3]被調(diào)用時(shí),b1對(duì)象中有一個(gè)閉包,引用了_fun_函數(shù)及外層函數(shù)變量n=1,所以匿名函數(shù)執(zhí)行的函數(shù)調(diào)用為_(kāi)fun_(2,1),輸出結(jié)果為1,并返回一個(gè)新的對(duì)象。
當(dāng)[4]執(zhí)行時(shí),b2對(duì)象也有一個(gè)閉包,引用了_fun_函數(shù)及外層函數(shù)變量n=2,執(zhí)行_fun_(3,2),輸出結(jié)果為2
var c=fun(0).fun(1);//undefined,0, c.fun(2);//1 c.fun(3); //1
能看懂前面的代碼執(zhí)行解釋,理解上面的代碼執(zhí)行輸出就不會(huì)有問(wèn)題了,希望大家喜歡。
- JS前端面試必備——基本排序算法原理與實(shí)現(xiàn)方法詳解【插入/選擇/歸并/冒泡/快速排序】
- 「中高級(jí)前端面試」JavaScript手寫(xiě)代碼無(wú)敵秘籍(推薦)
- js前端面試之同步與異步問(wèn)題詳解
- Javascript前端經(jīng)典的面試題及答案
- 前端面試知識(shí)點(diǎn)錦集(JavaScript篇)
- 前端JS面試中常見(jiàn)的算法問(wèn)題總結(jié)
- js前端面試題及答案整理(一)
- 一道常被人輕視的web前端常見(jiàn)面試題(JS)
- BAT及各大互聯(lián)網(wǎng)公司2014前端筆試面試題--JavaScript篇
- JS一次前端面試經(jīng)歷記錄
相關(guān)文章
Javascript表單特效之十大常用原理性樣例代碼大總結(jié)
開(kāi)頭說(shuō)這個(gè)常用原理性樣例,大家可能不太清楚,這篇文章主要是針對(duì)實(shí)際開(kāi)發(fā)中常用的一些代碼分析,主要是針對(duì)表單處理方法的一些資料,推薦大家收藏2016-07-07

JavaScript Generator函數(shù)使用分析

利用JS實(shí)現(xiàn)二叉樹(shù)遍歷算法實(shí)例代碼

JavaScript this指向相關(guān)原理及實(shí)例解析

設(shè)為首頁(yè)與加入收藏的JS代碼(多瀏覽器支持)