關(guān)于作用域的一些注意點(diǎn)以及理解閉包

先解釋一下什么是“自由變量”
在A作用域中使用的變量x,卻沒(méi)有在A作用域中聲明(在其他作用域中聲明),對(duì)于A作用域來(lái)說(shuō)猜丹,x就是一個(gè)自由變量

1 var x = 10;
2 function fn() {
3  var b = 20;
4   console.log(x+b);  // 這里x就是一個(gè)自由變量
5 }

如上程序中,在調(diào)用fn()函數(shù)時(shí)硅卢,函數(shù)體中第4行居触。取b的值就可以直接在 fn 作用域中取,因?yàn)? b 就是在這定義的老赤。但 x 的值轮洋,需要在另一個(gè)作用域中取,那么到哪個(gè)作用域中取呢抬旺?

有些說(shuō)法是到父作用域中取弊予,其實(shí)有時(shí)候這個(gè)說(shuō)法會(huì)產(chǎn)生歧義,如

1 var x = 10
2 function fn() {
3     console.log(x)
4 }
5 function show(f) {
6   var x = 20;
7   
8   (function () {
9       f();        // 10开财, 而不是20
10     })();
11  }
12 show(fn);

所以用上面的說(shuō)法汉柒,不太貼切误褪,這句話更為貼切 ------要到創(chuàng)建這個(gè)函數(shù)的那個(gè)作用域中取值---是“創(chuàng)建”而不是“調(diào)用”,切記切記 ----其實(shí)這就是所謂的靜態(tài)作用域

對(duì)于本文第一段代碼碾褂,在fn函數(shù)中兽间,取自由變量x的值時(shí),要到哪個(gè)作用域中日嘀略?——要到創(chuàng)建fn函數(shù)的那個(gè)作用域中取——無(wú)論fn函數(shù)將在哪里調(diào)用。

上面描述的只是跨一步作用域去尋找乓诽。

如果跨了一步帜羊,還沒(méi)找到呢?——接著跨鸠天!——一直跨到全局作用域?yàn)橹顾嫌R窃谌肿饔糜蛑卸紱](méi)有找到,那就是真的沒(méi)有了稠集。

這個(gè)一步一步“跨”的路線奶段,我們稱之為——作用域鏈。

我們拿文字總結(jié)一下取自由變量時(shí)的這個(gè)“作用域鏈”過(guò)程:(假設(shè)a是自由量)

第一步剥纷,現(xiàn)在當(dāng)前作用域查找a忧饭,如果有則獲取并結(jié)束。如果沒(méi)有則繼續(xù)筷畦;

第二步,如果當(dāng)前作用域是全局作用域刺洒,則證明a未定義鳖宾,結(jié)束;否則繼續(xù)逆航;

第三步鼎文,(不是全局作用域,那就是函數(shù)作用域)將創(chuàng)建該函數(shù)的作用域作為當(dāng)前作用域因俐;

第四步拇惋,跳轉(zhuǎn)到第一步。


圖片.png

以上代碼中:第13行抹剩,fn()返回的是bar函數(shù)撑帖,賦值給x。執(zhí)行x()澳眷,即執(zhí)行bar函數(shù)代碼胡嘿。取b的值時(shí),直接在fn作用域取出钳踊。取a的值時(shí)衷敌,試圖在fn作用域取勿侯,但是取不到,只能轉(zhuǎn)向創(chuàng)建fn的那個(gè)作用域中去查找缴罗,結(jié)果找到了助琐。

“閉包”概念不太好解釋
只需記住兩種情況就行了----==函數(shù)作為返回值,函數(shù)作為參數(shù)傳遞==

1 函數(shù)作為返回值

function fn() {
    var max = 10;
    return function bar(x) {
        if ( x > max ){
            console.log(x);
      }
    }
}

var f1 = fn()
f1(15)    // 15

如上代碼面氓,bar函數(shù)作為返回值兵钮,賦值給f1變量。執(zhí)行f1(15)時(shí)侧但,用到了fn作用域下的max變量的值矢空。至于如何跨作用域取值,可以參考上面禀横。

2 函數(shù)作為參數(shù)被傳遞

var max = 10,
      fn = function (x) {
          if ( x > max ){
                 console.log(x);
           }
      };
( function (f) {
    var max = 100;
    f(15);
})( fn );
// 15    

如上代碼中屁药,fn函數(shù)作為一個(gè)參數(shù)被傳遞進(jìn)入另一個(gè)函數(shù),賦值給f參數(shù)柏锄。執(zhí)行f(15)時(shí)酿箭,max變量的取值是10,而不是100趾娃。

上面講到自由變量跨作用域取值時(shí)缭嫡,曾經(jīng)強(qiáng)調(diào)過(guò):==要去創(chuàng)建這個(gè)函數(shù)的作用域取值,而不是“父作用域”==抬闷。理解了這一點(diǎn)妇蛀,以上兩端代碼中,自由變量如何取值應(yīng)該比較簡(jiǎn)單笤成。(不明白的朋友一定要去上面看看评架,這個(gè)很重要!)

另外炕泳,講到閉包纵诞,除了結(jié)合著作用域之外,還需要結(jié)合著執(zhí)行上下文棧來(lái)說(shuō)一下培遵。

執(zhí)行上下文椪丬剑可以看這篇(http://www.cnblogs.com/wangfupeng1988/p/3989357.html

其實(shí)調(diào)用函數(shù)會(huì)進(jìn)行上下文環(huán)境的壓棧,當(dāng)一個(gè)函數(shù)被調(diào)用完成之后籽腕,其執(zhí)行上下文環(huán)境將被銷毀嗡呼,其中的變量也會(huì)被同時(shí)銷毀。

但是在當(dāng)時(shí)那篇文章中留了一個(gè)問(wèn)號(hào)——有些情況下皇耗,函數(shù)調(diào)用完成之后晤锥,其執(zhí)行上下文環(huán)境不會(huì)接著被銷毀。這就是需要理解閉包的核心內(nèi)容。

稍微分析一下


圖片.png

第一步矾瘾,代碼執(zhí)行前生成全局上下文環(huán)境女轿,并在執(zhí)行時(shí)對(duì)其中變量進(jìn)行賦值。此時(shí)全局上下文環(huán)境是活動(dòng)狀態(tài)


圖片.png

第二步壕翩,執(zhí)行第17行代碼時(shí)蛉迹,調(diào)用fn(),產(chǎn)生fn()執(zhí)行上下文環(huán)境放妈,壓棧北救,并設(shè)置為活動(dòng)狀態(tài)。


圖片.png

第三步芜抒,執(zhí)行完17行珍策,fn()調(diào)用完成。按理說(shuō)應(yīng)該銷毀掉 fn() 的執(zhí)行上下文環(huán)境宅倒,但是這里不能這么做攘宙。注意重點(diǎn)來(lái)了:因?yàn)閳?zhí)行 fn() 時(shí),返回的是一個(gè)函數(shù)拐迁。函數(shù)特別之處是可以創(chuàng)建一個(gè)獨(dú)立的作用域蹭劈,而返回的這個(gè)函數(shù)體中,有一個(gè)自由變量 max 要引用 fn 作用域下的 fn() 上下文環(huán)境中的max线召。因此這個(gè) max 不能被銷毀铺韧,銷毀之后 bar 函數(shù)中的 max 就找不到值了

因此,這里的 fn() 上下文環(huán)境不能被銷毀缓淹,還依然存在于執(zhí)行上下文棧中哈打。
-- 即,執(zhí)行到
第18行時(shí)讯壶,全局上下文環(huán)境將變?yōu)榛顒?dòng)狀態(tài)料仗,但是fn()上下文環(huán)境依然會(huì)在執(zhí)行上下文棧中。另外鹏溯,執(zhí)行完第18行,全局上下文環(huán)境中的max被賦值為100淹仑。如下圖:


圖片.png

第四步丙挽,執(zhí)行到第20行,執(zhí)行f1(15)匀借,即執(zhí)行bar(15)颜阐,創(chuàng)建bar(15)上下文環(huán)境,并將其設(shè)置為活動(dòng)狀態(tài)吓肋。


圖片.png

執(zhí)行bar(15)時(shí)凳怨,max是自由變量,需要向創(chuàng)建bar函數(shù)的作用域中查找,找到了max的值為10肤舞。

這里的重點(diǎn)就在于紫新,創(chuàng)建bar函數(shù)是在執(zhí)行fn()時(shí)創(chuàng)建的。==fn()早就執(zhí)行結(jié)束了李剖,但是fn()執(zhí)行上下文環(huán)境還存在與棧中芒率,因此bar(15)時(shí),max可以查找到篙顺。如果fn()上下文環(huán)境銷毀了偶芍,那么max就找不到了==

使用閉包會(huì)增加內(nèi)容開(kāi)銷,現(xiàn)在很明顯了吧德玫!

第五步匪蟀,執(zhí)行完20行就是上下文環(huán)境的銷毀過(guò)程,這里就不再贅述了宰僧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末材彪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子撒桨,更是在濱河造成了極大的恐慌查刻,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凤类,死亡現(xiàn)場(chǎng)離奇詭異穗泵,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)谜疤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門佃延,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人夷磕,你說(shuō)我怎么就攤上這事履肃。” “怎么了坐桩?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵尺棋,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我绵跷,道長(zhǎng)膘螟,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任碾局,我火速辦了婚禮荆残,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘净当。我一直安慰自己内斯,他們只是感情好蕴潦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著俘闯,像睡著了一般潭苞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上备徐,一...
    開(kāi)封第一講書(shū)人閱讀 51,708評(píng)論 1 305
  • 那天萄传,我揣著相機(jī)與錄音,去河邊找鬼蜜猾。 笑死秀菱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蹭睡。 我是一名探鬼主播衍菱,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼肩豁!你這毒婦竟也來(lái)了脊串?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤清钥,失蹤者是張志新(化名)和其女友劉穎琼锋,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體祟昭,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缕坎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了篡悟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谜叹。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖搬葬,靈堂內(nèi)的尸體忽然破棺而出荷腊,到底是詐尸還是另有隱情,我是刑警寧澤急凰,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布女仰,位于F島的核電站,受9級(jí)特大地震影響抡锈,放射性物質(zhì)發(fā)生泄漏疾忍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一企孩、第九天 我趴在偏房一處隱蔽的房頂上張望锭碳。 院中可真熱鬧袁稽,春花似錦勿璃、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)歧沪。三九已至,卻和暖如春莲组,著一層夾襖步出監(jiān)牢的瞬間诊胞,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工锹杈, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留撵孤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓竭望,卻偏偏與公主長(zhǎng)得像邪码,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子咬清,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355