02.【JS讀書筆記】循環(huán)和閉包

作用域閉包

function foo() {
    var a = 2;
    
    function bar () {       //bar()的詞法作用域能夠訪問foo()的內(nèi)部作用域
        console.log(a);
    }
    
    return bar;  //然后將bar()函數(shù)本身當(dāng)做一個(gè)值進(jìn)行傳遞
}

var baz = foo();        //foo()執(zhí)行后,其返回值(即內(nèi)部的bar()函數(shù))賦值給變量baz
baz();          //2 —— 閉包的效果 

通常來說,foo()函數(shù)執(zhí)行后,其整個(gè)內(nèi)部作用域都會(huì)被銷毀(垃圾回收機(jī)制),而閉包的“神奇”之處正是可以阻止這件事發(fā)生。

bar()依然持有對(duì)foo()內(nèi)部作用域的引用,這個(gè)引用就叫做閉包。

閉包使得函數(shù)可以繼續(xù)訪問定義時(shí)的詞法作用域。

循環(huán)和閉包

預(yù)期希望分別輸出數(shù)字1-5,每秒一次,每次一個(gè);

但實(shí)際上,代碼運(yùn)行時(shí)會(huì)已每秒一次的頻率輸出5次6(6產(chǎn)生的原因:循環(huán)的終止條件是i不再<= 5,條件首次成立時(shí)的值是6.故輸出顯示的是循環(huán)結(jié)束時(shí)i的最終值。)。

for (var i = 1; i <= 5; i++) {
    setTimeout(function timer(){
        console.log(i);
    },i * 1000);
};

根據(jù)作用域的工作原理,實(shí)際情況為:盡管循環(huán)中的五個(gè)函數(shù)是在各個(gè)迭代中分別定義的,但他們都被封閉在一個(gè)共享的全局作用域中,因此實(shí)際上只有一個(gè)i。
故我們需要更多的閉包作用域,特別是在循環(huán)過程中每個(gè)迭代都需要一個(gè)閉包作用域。

方法一:用IIFE產(chǎn)生閉包解決

IIFE(立即執(zhí)行函數(shù))會(huì)通過聲明并立即執(zhí)行一個(gè)函數(shù)來創(chuàng)建作用域。但若作用域?yàn)榭?,僅將其封閉是不夠的,故IIFE需要有自己的變量,用來在每個(gè)迭代中儲(chǔ)存i的值:

for (var i = 1; i <= 5; i++) {
    (function(){
        var j = i;      //IIFE需要有自己的變量,用來在每個(gè)迭代中儲(chǔ)存i的值
        setTimeout (function timer (
            console.log(j);
        ),j * 1000);
    })();
}

將這段代碼進(jìn)行改進(jìn)之后:

for (var i = 1; i <= 5; i++) {
    (function(j){       //IIFE需要有自己的變量,用來在每個(gè)迭代中儲(chǔ)存i的值
        setTimeout (function timer (   //在迭代內(nèi)使用IIFE會(huì)為每個(gè)迭代都生成一個(gè)新的作用域
            console.log(j);     //使得setTimeout函數(shù)的回調(diào)可以將新的作用域封閉在每個(gè)迭代的內(nèi)部
        ),j * 1000);
    })(i);
}

方法二:let

for (var i = 1; i <= 5; i++) {
    let j = i;      // 用let聲明可以劫持塊作用域,并在塊作用域中聲明一個(gè)變量
    setTimeout(function timer(){
        console.log(j);
    },j * 1000);
}

或者直接在for循環(huán)頭部用let聲明:

for (let i = 1; i <= 5; i++) {
    setTimeout(function timer(){
        console.log(i);
    },i * 1000);
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 5,711評(píng)論 16 88
  • 特別說明,為便于查閱,文章轉(zhuǎn)自https://github.com/getify/You-Dont-Know-JS...
    殺破狼real閱讀 553評(píng)論 0 0
  • 函數(shù)只能在其所在的作用域內(nèi)調(diào)用嗎?怎樣在一個(gè)函數(shù)所在的作用域之外調(diào)用該函數(shù)?比如下面代碼,函數(shù)bar定義在函數(shù)fo...
    閆浩奇閱讀 556評(píng)論 0 4
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 2,366評(píng)論 0 21
  • 我獨(dú)自一人在這里 然而我并不是我也不在這里我穿著昨日的影像伸出發(fā)霉的手挖掘曾經(jīng)的那漏壺般的故事 我睜開眼睛看見未來...
    游天杰閱讀 180評(píng)論 0 3

友情鏈接更多精彩內(nèi)容