1. 程式人生 > 實用技巧 >JS - 閉包

JS - 閉包

可能大多數人平時大量寫js程式碼,但是對閉包還是模模糊糊。本文記錄自己學習閉包的一些知識點。

function foo() {
    var a = 2;
    function bar() {
        console.log(a)
    };
    return bar;
}

var result = foo()  // result就是foo返回的bar
result() // 呼叫了bar,成功訪問了函式作用域中的變數a

以上就是一個閉包的程式碼。foo()執行後,foo()內部作用域會被銷燬,JS垃圾回收器回收無用的空間,釋放記憶體。但是由於閉包的存在,會使它一直存在。因為bar()本身在使用這個作用域。bar()對foo()作用域的引用就叫閉包。

傳遞函式的方式觀察閉包,通過內部函式baz傳遞過來,由於baz涵蓋了foo作用域,所以能夠訪問到a

function foo() {
    var a;
    function bar() {
        console.log(a)
    }
    baz(bar)
}

function baz(fn) {
  fn()   //這就是閉包
}

在平時編碼過程中,閉包隨處可見。比如將函式作為引數到處傳,那麼就會在這些函式呼叫中找到閉包。比如平時常見的定時器。

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

以上程式碼,我們期望它能每一秒依次輸出1-5,但是其實它的結果是 6 個 6,這是由於 i 其實是一個全域性作用域,並沒有在每次迴圈中儲存。for迴圈到最後i的結果是6。

我們可以通過閉包來解決這種問題,將每次迴圈的i值傳入閉包函式中進行儲存。

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

es6中新增了let,也可以解決以上問題,更加簡便。

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