亂談閉包

關於閉包,有各類各樣的解釋,百科給出的解釋是:數組

在計算機科學中,閉包(英語:Closure),又稱詞法閉包(Lexical Closure)或函數閉包(function closures),是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在,即便已經離開了創造它的環境也不例外。因此,有另外一種說法認爲閉包是由函數和與其相關的引用環境組合而成的實體。閉包在運行時能夠有多個實例,不一樣的引用環境和相同的函數組合能夠產生不一樣的實例。閉包

個人理解是:函數執行造成私有的做用域。 那麼他就有兩個做用:保護和保存。app

閉包的保護做用

閉包造成的私有做用域能夠保護裏面的私有變量不受外界干擾。例如咱們常常使用的:函數

var a = 5;
(function () {
    var a = 10;
    console.log(a)   // ---->10
})()
console.log(a)   // ---->5
複製代碼

這時在全局中有個a變量,私有做用域中也有個a變量,使用閉包,咱們再修改私有做用域中的同名變量是,不會對全局產生影響,避免形成全局污染。post

閉包的保存做用

造成一個不銷燬的私有做用域,保護函數執行的上下文。例如以前咱們寫函數的防抖和節流的時候:ui

function debounce(fn, time) {
    let Timer;
    return () => {
        Timer && clearTimeout(Timer)
        Timer = setTimeout(() => {
            fn.apply(this, arguments)
        }, time)
    }
}
複製代碼

debounce函數保存了一個計時器id的變量Timer,debounce執行 造成一個可讓返回函數訪問到的私有做用域(函數的上級做用域是它定義時所處的做用域),每次調用返回函數的時候均可以訪問獲得這個Timer。this

閉包的反作用

舉個總是被拿來舉的閉包例子:spa

var liList = document.querySelectorAll('li')
for (var i = 0; i < liList.length; i++) {
    (function (i) {
        liList[i].onclick = function () {
            console.log(i)
        }
    })(i)
}
複製代碼

因爲返回的函數被外部的onclick事件引用了,閉包造成的私有做用域沒法被銷燬,內存沒法被回收,回收機制參考js垃圾回收機制,容易形成內存泄漏。code

若要手動釋放內存,則那麼寫:事件

for (var i = 0; i < liList.length; i++) {
    liList[i].onclick = null
}
複製代碼

並非全部閉包都會形成內存沒法回收,例如:

function fn(i) {
    return function (n){
        console.log(i + n)
    }
}

fn(2)(3)
複製代碼

fn造成的私有做用於中,變量並無被外界所引用,函數執行完成後,內存馬上進行回收。

相關文章
相關標籤/搜索