我的JS筆記 -- 閉包


閉包是JS中一個(gè)很重要的概念蟹漓,閉包其實(shí)是基于詞法作用域規(guī)則實(shí)現(xiàn)的,詞法作用域規(guī)則會(huì)使函數(shù)在查找變量時(shí)從函數(shù)內(nèi)部再到函數(shù)定義時(shí)的作用域源内,而不是從函數(shù)內(nèi)部到函數(shù)使用時(shí)的作用域牧牢。所以無(wú)論函數(shù)在哪里被調(diào)用,也無(wú)論它如何被調(diào)用姿锭,它的詞法作用域都只由函數(shù)被聲明時(shí)所處的位置決定塔鳍。

基于這個(gè)規(guī)則,那么函數(shù)在當(dāng)前詞法作用域之外執(zhí)行呻此,也可以記住并訪問(wèn)函數(shù)聲明時(shí)所在的詞法作用域轮纫,這時(shí)就產(chǎn)生了閉包。

高程定義閉包:閉包是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)焚鲜。

function f1() {
    var a = 1; // 3.調(diào)用的函數(shù)內(nèi)部使用了父級(jí)作用域的內(nèi)部變量
    function f2() { // 1.調(diào)用的函數(shù)是父級(jí)作用域內(nèi)部聲明的
        console.log(a);
    }
    return f2;
}
var f3 = f1(); // 2.調(diào)用的函數(shù)是在父級(jí)作用域之外進(jìn)行調(diào)用掌唾,foo()執(zhí)行后將bar 函數(shù)本身當(dāng)作一個(gè)值類型進(jìn)行傳遞給baz。
f3(); // 這就是閉包的效果忿磅。執(zhí)行之后糯彬,輸出f1中的a,因?yàn)椴徽摵螘r(shí)何處調(diào)用f2都能訪問(wèn)f1的變量所以f1不會(huì)被回收

閉包產(chǎn)生條件

通過(guò)以上代碼葱她,我們可以得到閉包產(chǎn)生的條件:

  1. 調(diào)用的函數(shù)是父級(jí)作用域內(nèi)部聲明的撩扒;
  2. 調(diào)用的函數(shù)是在父級(jí)作用域之外進(jìn)行調(diào)用;
  3. 調(diào)用的函數(shù)內(nèi)部使用了父級(jí)作用域的內(nèi)部變量吨些;

總結(jié)便是:無(wú)論使用何種方式對(duì)函數(shù)類型的值進(jìn)行傳遞搓谆,當(dāng)函數(shù)在別處被調(diào)用時(shí)都可以觀察到閉包。

// 無(wú)論通過(guò)何種手段將內(nèi)部函數(shù)傳遞到所在的詞法作用域以外豪墅, 它都會(huì)持有對(duì)原始定義作用域的引用泉手,無(wú)論在何處執(zhí)行這個(gè)函數(shù)都會(huì)使用閉包。

function foo1() {
    var a = 1;
    function baz1() {
        console.log(a); // 1
    }
    bar1(baz1); // baz1被作為參數(shù)傳遞到外部函數(shù)bar1中
}
function bar1(fn) {
    fn(); // 這就是閉包偶器!
}
foo1();

var fn2;
function foo2() {
    var a = 2;
    function baz2() {
        console.log(a);
    }
    fn2 = baz2; // 將 baz2分配給全局變量斩萌,也相當(dāng)于傳遞到外部
}
function bar2() {
    fn2(); // 這就是閉包!
}
foo2();
bar2(); // 2

// 主要看看是否是外部調(diào)用屏轰。因?yàn)橛脩酎c(diǎn)擊時(shí)觸發(fā)事件颊郎,不是在foo3中內(nèi)部調(diào)用的。
var foo3 = function () {
    var btn = document.querySelector("#myBtn");
    var a = 3;
    btn.onclick = function () {
        alert(a);
    }
}
foo3();

下面是一個(gè)關(guān)于閉包的金典例子:

for (var i = 1; i <= 5; i++) { // 只有一個(gè)全局作用域亭枷,運(yùn)行timer是尋找變量i只有全局的i = 6
    setTimeout(function timer() {
        console.log(i); // 運(yùn)行時(shí)會(huì)以每秒一次的頻率輸出五次 6
    }, i * 1000);
}
// 首先解釋6是從哪里來(lái)的袭艺。 這個(gè)循環(huán)的終止條件是i不再<=5。 條件首次成立時(shí)i的值是6叨粘。因此猾编,輸出顯示的是循環(huán)結(jié)束時(shí)i的最終值瘤睹。延遲函數(shù)的回調(diào)會(huì)在循環(huán)結(jié)束時(shí)才執(zhí)行。事實(shí)上答倡,當(dāng)定時(shí)器運(yùn)行時(shí)即使每個(gè)迭代中執(zhí)行的是setTimeout(.., 0)轰传,所有的回調(diào)函數(shù)依然是在循環(huán)結(jié)束后才會(huì)被執(zhí)行,因此會(huì)每次輸出一個(gè)6出來(lái)瘪撇。

for (var i = 1; i <= 5; i++) { 
    // 每次循環(huán)創(chuàng)建一個(gè)立即函數(shù)获茬,產(chǎn)生一個(gè)新的作用域
    (function (j) { // 利用立即函數(shù),每次循環(huán)創(chuàng)建單獨(dú)的函數(shù)作用域并捕獲每次循環(huán)的i作為參數(shù)傳入倔既,timer函數(shù)是一個(gè)閉包恕曲,它在立即函數(shù)中聲明,在setTimeOut回調(diào)使用渤涌,它會(huì)保留傳入的參數(shù)i的值佩谣,當(dāng)延遲函數(shù)在作用域之外調(diào)用時(shí),仍能訪問(wèn)到i
        setTimeout(function timer() {
            console.log(j); // 能夠正常輸出1, 2, 3, 4, 5
        }, j * 1000);
    })(i);
}

閉包作用

閉包的最大用處有兩個(gè)实蓬,一個(gè)是可以讀取函數(shù)內(nèi)部的變量茸俭,另一個(gè)就是讓這些變量始終保持在內(nèi)存中。函數(shù)的執(zhí)行上下文安皱,在執(zhí)行完畢之后调鬓,生命周期結(jié)束,那么該函數(shù)的執(zhí)行上下文就會(huì)失去引用酌伊。其占用的內(nèi)存空間很快就會(huì)被垃圾回收器釋放腾窝。可是閉包的存在腺晾,會(huì)阻止這一過(guò)程雖然例子中的閉包被保存在了全局變量中燕锥,但是閉包的作用域鏈并不會(huì)發(fā)生任何改變辜贵。在閉包中悯蝉,能訪問(wèn)到的變量,仍然是作用域鏈上能夠查詢到的變量即閉包可以使得它誕生環(huán)境一直存在托慨。請(qǐng)看下面的例子鼻由,閉包使得內(nèi)部變量記住上一次調(diào)用時(shí)的運(yùn)算結(jié)果:

function addNum(num) {
    return function () {
        return num++;
    };
}
var add = addNum(1);
add() // 1
add() // 2
add() // 3
// 上面代碼中,num是函數(shù)addNum的內(nèi)部變量厚棵。通過(guò)閉包蕉世,start的狀態(tài)被保留了,每一次調(diào)用都是在上一次調(diào)用的基礎(chǔ)上進(jìn)行計(jì)算婆硬。從中可以看到狠轻,閉包add使得函數(shù)addNum的內(nèi)部環(huán)境,一直存在彬犯。所以向楼,閉包可以看作是函數(shù)內(nèi)部作用域的一個(gè)接口

更多文章在 這里 查吊,覺(jué)得不錯(cuò)希望點(diǎn)個(gè) star

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市湖蜕,隨后出現(xiàn)的幾起案子逻卖,更是在濱河造成了極大的恐慌,老刑警劉巖昭抒,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件评也,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡灭返,警方通過(guò)查閱死者的電腦和手機(jī)盗迟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)熙含,“玉大人诈乒,你說(shuō)我怎么就攤上這事∑怕” “怎么了怕磨?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)消约。 經(jīng)常有香客問(wèn)我肠鲫,道長(zhǎng),這世上最難降的妖魔是什么或粮? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任导饲,我火速辦了婚禮,結(jié)果婚禮上氯材,老公的妹妹穿的比我還像新娘渣锦。我一直安慰自己,他們只是感情好氢哮,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布袋毙。 她就那樣靜靜地躺著,像睡著了一般冗尤。 火紅的嫁衣襯著肌膚如雪听盖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天裂七,我揣著相機(jī)與錄音皆看,去河邊找鬼。 笑死背零,一個(gè)胖子當(dāng)著我的面吹牛腰吟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播徙瓶,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼毛雇,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼录语!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起禾乘,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤澎埠,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后始藕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蒲稳,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年伍派,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了江耀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诉植,死狀恐怖祥国,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晾腔,我是刑警寧澤舌稀,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站灼擂,受9級(jí)特大地震影響壁查,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜剔应,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一睡腿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧峻贮,春花似錦席怪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至嚼黔,卻和暖如春细层,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唬涧。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盛撑,地道東北人碎节。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像抵卫,于是被迫代替她去往敵國(guó)和親狮荔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胎撇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 談起閉包晚树,它可是JavaScript兩個(gè)核心技術(shù)之一(異步和閉包),在面試以及實(shí)際應(yīng)用當(dāng)中,我們都離不開它們雅采,甚至...
    sponing閱讀 674評(píng)論 0 7
  • 閉包(closure)是Javascript語(yǔ)言的一個(gè)難點(diǎn)爵憎,也是它的特色,很多高級(jí)應(yīng)用都要依靠閉包實(shí)現(xiàn)婚瓜。 一宝鼓、變量...
    zock閱讀 1,074評(píng)論 2 6
  • 閉包: 官方”的解釋是:閉包是一個(gè)擁有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個(gè)函數(shù)),因而這些變量也是該...
    小裁縫sun閱讀 610評(píng)論 0 5
  • 究竟什么是閉包? 閉包在什么場(chǎng)景下使用胡陪? 寫前端程序需要用到閉包嗎沥寥?我用jQuery也能寫的好好滴呀? 對(duì)于初學(xué)者...
    佩吉秋閱讀 17,430評(píng)論 9 111
  • 系統(tǒng)預(yù)設(shè)風(fēng)險(xiǎn)柠座,根據(jù)系統(tǒng)返回的常用數(shù)據(jù)营曼,可以右滑添加,不可刪除: 自定義預(yù)設(shè)風(fēng)險(xiǎn)愚隧,根據(jù)自己需求蒂阱,可以右上角添加,左滑...
    仝小六閱讀 230評(píng)論 0 1