function fun(n,o)這是一道非常典型的js閉包問題。其中巢狀了三層fun函式,搞清楚每層fun的函式是那個fun函式尤為重要。可以先在紙上或其他地方寫下你認為的結果,然後展開看看正確答案是什麼?};}var a = fun(0); a.fun(1); a.fun(2); a.fun(3);//
undefined,?,?,?
var b = fun(0).fun(1).fun(2).fun(3);//
undefined,?,?,?
var c = fun(0).fun(1); c.fun(2); c.fun(3);//
undefined,?,?,?
//問:三行a,b,c的輸出分別是什麼?
//要分析此問題,我們需要了解:答案://
a: undefined,0,0,0
//b: undefined,0,1,2
//c: undefined,0,1,1
這段****現了三個fun函式,所以第一步先搞清楚,這三個fun函式的關係,哪個函式與哪個函式是相同的。
function fun(n,o) };}先看第乙個fun函式,屬於標準具名函式宣告,是新建立的函式,他的返回值是乙個物件字面量表示式,屬於乙個新的object。這個新的物件內部包含乙個也叫fun的屬性,屬於匿名函式表示式,即fun這個屬性中存放的是乙個新建立匿名函式表示式。
注意:所有宣告的匿名函式都是乙個新函式。
所以第乙個fun函式與第二個fun函式不相同,均為新建立的函式。
再說第三個fun函式之前需要先說下,在函式表示式內部能不能訪問存放當前函式的變數。
測試1,物件內部的函式表示式:
var o=測試2,非物件內部的函式表示式:};o.fn();
//error報錯:fn is not defined
var fn=function ();fn();
//function ();正確
結論是:使用 var 或是非物件內部的函式表示式內,可以訪問到存放當前函式的變數;在物件內部的則不能訪問到。
原因也非常簡單,因為函式作用域鏈的問題,採用var的是在外部建立了乙個fn變數,函式內部當然可以在內部尋找不到 fn 後向上級作用域查詢 fn,而在建立物件內部時,因為沒有在函式作用域內建立 fn,所以無法訪問。
所以綜上所述,可以得知,最內層的return出去的fun函式不是第二層fun函式,是最外層的fun函式。
所以,三個fun函式的關係也理清楚了,第乙個等於第三個,他們都不等於第二個。
再看下原題,現在知道了程式中有兩個fun函式(第乙個和第三個相同),遂接下來的問題是搞清楚,執行時他執行的是哪個fun函式?
1、第一行a
var a = fun(0); a.fun(1); a.fun(2); a.fun(3);可以得知,第乙個fun(0)是在呼叫第一層fun函式。第二個fun(1)是在呼叫前乙個fun的返回值的fun函式,所以:後面幾個fun(1),fun(2),fun(3),函式都是在呼叫第二層fun函式。因此:在第一次呼叫fun(0)時,o為undefined;
第二次呼叫fun(1)時m為1,此時fun閉包了外層函式的n,也就是第一次呼叫的n=0,即m=1,n=0,並在內部呼叫第一層fun函式fun(1,0);所以o為0;
第三次呼叫fun(2)時m為2,但依然是呼叫a.fun,所以還是閉包了第一次呼叫時的n,所以內部呼叫第一層的fun(2,0);所以o為0
第四次同理;
即:最終答案為undefined,0,0,0
2、第二行b
var b = fun(0).fun(1).fun(2).fun(3);先從fun(0)開始看,肯定是呼叫的第一層fun函式;而他的返回值是乙個物件,所以第二個fun(1)呼叫的是第二層fun函式,後面幾個也是呼叫的第二層fun函式。因此:在第一次呼叫第一層fun(0)時,o為undefined;
第二次呼叫 .fun(1)時m為1,此時fun閉包了外層函式的n,也就是第一次呼叫的n=0,即m=1,n=0,並在內部呼叫第一層fun函式fun(1,0);所以o為0;
第三次呼叫 .fun(2)時m為2,此時當前的fun函式不是第一次執行的返回物件,而是第二次執行的返回物件。而在第二次執行第一層fun函式時時(1,0)所以n=1,o=0,返回時閉包了第二次的n,遂在第三次呼叫第三層fun函式時m=2,n=1,即呼叫第一層fun函式fun(2,1),所以o為1;然後閉包了第三次的n就為2了。
第四次呼叫 .fun(3)時m為3,閉包了第三次呼叫的n,同理,最終呼叫第一層fun函式為fun(3,2);所以o為2;
即最終答案:undefined,0,1,2
3、第三行c
var c = fun(0).fun(1); c.fun(2); c.fun(3);根據前面兩個例子,可以得知:fun(0)為執行第一層fun函式,.fun(1)執行的是fun(0)返回的第二層fun函式,這裡語句結束,因此c存放的是fun(1)的返回值,而不是fun(0)的返回值,所以c中閉包的也是fun(1)第二次執行的n的值。c.fun(2)執行的是fun(1)返回的第二層fun函式,c.fun(3)執行的也是fun(1)返回的第二層fun函式。因此:
在第一次呼叫第一層fun(0)時,o為undefined;
第二次呼叫 .fun(1)時m為1,此時fun閉包了外層函式的n(即n=1了),也就是第一次呼叫的n=0,即m=1,n=0,並在內部呼叫第一層fun函式fun(1,0);所以o為0;
第三次呼叫 .fun(2)時m為2,此時fun閉包的是第二次呼叫的n=1,即m=2,n=1,並在內部呼叫第一層fun函式fun(2,1);所以o為1;
第四次.fun(3)時同理,但依然是呼叫的第二次的返回值,遂最終呼叫第一層fun函式fun(3,1),所以o還為1
即最終答案:undefined,0,1,1
分析該問題主要需要了解函式作用域鏈的問題,這樣就能清楚第乙個fun其實是和第三個fun是一樣的;
其次就是需要了解閉包的知識,如果要我說什麼是閉包,我認為,廣義上的閉包就是指乙個變數在他自身作用域外被使用了,就叫發生了閉包。所以當第三個fun執行時,閉包將m的值繫結到了n上
js深入理解之作用域鏈
語法分析,分析3樣東西 第1步 先分析引數 第2步 再分析變數宣告 第3步 分析函式宣告 乙個函式能使用的區域性變數,就從上面的3步分析而來 具體步驟 0 函式執行前的1瞬間,生成 active object 活動物件 下稱ao 1 1.1 函式宣告的引數,形成ao的屬性,值全是undefined,...
深入理解JS閉包
閉包 closure 是j acript語言的乙個難點,也是它的特色,很多高階應用都要依靠閉包實現。一 變數的作用域 要理解閉包,首先必須理解j ascript特殊的變數作用域。變數的作用域無非就是兩種 全域性變數和區域性變數。j ascript語言的特殊之處,就在於函式內部可以直接讀取全域性變數。...
JS深入理解作用域 作用域鏈,變數提公升
1 作用域 1 全域性作用域 在瀏覽器載入我們html頁面的時候,首先會開闢乙個供js 執行的環境,即全域性作用域,這是乙個棧記憶體 2 私有作用域 函式執行時,開闢乙個新的棧記憶體,形成私有作用域 2 基本資料型別與引用資料型別區別?基本資料型別 string,number,boolean,nul...