我眼中閉包的原理

閉包幾乎是通往高級前端工程師所必須經(jīng)過的一個門檻。在這方面看過很多資料,感覺許多文章都只是提到了閉包的實現(xiàn),而沒有涉及閉包的原理。

在談閉包之前需要先了解幾個相關的概念:

1、變量作用域:全局變量擁有全局作用域,在js代碼的任何地方都可見。在函數(shù)內(nèi)部聲明的變量只在該函數(shù)體內(nèi)可見,被稱為局部變量。

2、函數(shù)作用域:在函數(shù)內(nèi)聲明的所有變量在該函數(shù)體內(nèi)始終是可見的。

3、作用域鏈:作用域鏈是一個對象。作用域鏈中定義了該作用域內(nèi)的變量,它保證了該作用域中變量、函數(shù)的有序訪問。

4、作用域鏈的創(chuàng)建:定義一個函數(shù)時,會保存一個作用域鏈。調(diào)用一個函數(shù)時,會創(chuàng)建一個新的對象來存儲其局部變量,并將該對象添加至保存的作用域鏈上,同時創(chuàng)建一個新的更長的表示函數(shù)調(diào)用作用域的鏈。對于嵌套函數(shù)來說,每調(diào)用一次外部函數(shù),都會創(chuàng)建一個新的作用域鏈,所以每次調(diào)用外部函數(shù),雖然其內(nèi)部代碼相同,但是調(diào)用的作用域鏈是不同的。

5、垃圾回收機制:js具有自動垃圾回收機制,會定期把不再使用的變量銷毀,釋放其占用的內(nèi)存。(只會銷毀局部變量,全局變量的生命周期只有在頁面或瀏覽器關閉時才會結束)

閉包的原理:函數(shù)的執(zhí)行依賴于函數(shù)定義時的作用域鏈,即js函數(shù)執(zhí)行時用的作用域鏈是該函數(shù)定義時創(chuàng)建的作用域鏈。大多數(shù)時候定義函數(shù)時的作用域鏈在函數(shù)執(zhí)行時仍然有效。但是如果定義函數(shù)時的作用域鏈和執(zhí)行函數(shù)時的作用域鏈不同時,就會出現(xiàn)問題。即當一個函數(shù)中嵌套了另一個函數(shù),并把嵌套的函數(shù)對象作為返回值返回時,就會產(chǎn)生這種情況。

定義函數(shù)的作用域鏈和執(zhí)行時相同
外部函數(shù)把嵌套函數(shù)作為返回值返回時

第一個例子很容易理解。但是第二個,可以看到當外部函數(shù)把嵌套函數(shù)作為返回值返回時,其執(zhí)行結果仍然是局部變量的值,而不是全局變量的值。這就是因為函數(shù)執(zhí)行時用到的作用域鏈,其實是函數(shù)定義時創(chuàng)建的。不管該函數(shù)在何時何地執(zhí)行,它通過作用域鏈最先找到的變量就是相同外部函數(shù)中定義的變量。而閉包正是利用這種特性實現(xiàn)的:閉包可以捕捉到局部變量或參數(shù),并一直保存下來,使其不會被當成垃圾回收。

閉包和垃圾回收的關系:調(diào)用函數(shù)時,會創(chuàng)建一個對象來保存其局部變量,并且把這個對象添加到作用域鏈上。當函數(shù)返回時(即執(zhí)行完成了),就會從作用域鏈中把綁定局部變量的對象刪除,這個對象就會被當作垃圾回收。但是如果定義了嵌套函數(shù),那么嵌套函數(shù)也會有自己相應的作用域鏈,它與外部函數(shù)一樣,把其局部變量保存到一個對象上,如果嵌套函數(shù)是作為返回值返回的或者存儲在某處的屬性里,那么就會有一個外部引用指向這個嵌套函數(shù),那么外部函數(shù)就不會被當作垃圾回收,它在作用域鏈中綁定局部變量的對象也不會被回收。

閉包的應用場景:實現(xiàn)私有成員;保護命名空間;避免污染全局變量;可以使變量長期駐留在內(nèi)存中。這是在網(wǎng)上找的,不是特別好理解。其實可以參考jQuery的源碼,它就是將所有的代碼封裝到了一個閉包里邊的。下邊是我之前寫的一段代碼,再根據(jù)閉包進行的改寫:

改寫之前的代碼
根據(jù)閉包原理改寫后的代碼

在改寫后的代碼中,定義了2個閉包,這2個閉包共享同一個變量defaultSize??梢钥闯鍪褂瞄]包對代碼的封裝,避免全局變量的污染有很大的作用。

使用閉包的注意事項:當然閉包也不是十全十美,它可以把局部變量長期保存到內(nèi)存中,不被當作垃圾回收,這種特性如果使用不當,很容易會造成內(nèi)存泄漏。建議還是多看看其它比較成熟的框架是怎么使用閉包的,會對提高個人代碼的質(zhì)量有很大的幫助。

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

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

  • 前言 對于js中的閉包,無論是老司機還是小白,我想,見得不能再多了,然而有時三言兩語卻很難說得明白,反正在我初學時...
    itclanCoder閱讀 4,297評論 1 11
  • 閉包(closure)是Javascript語言的一個難點,也是它的特色,很多高級應用都要依靠閉包實現(xiàn)。 一、變量...
    zouCode閱讀 1,362評論 0 13
  • 作用域和閉包是 JavaScript 最重要的概念之一,想要進一步學習 JavaScript,就必須理解 Java...
    劼哥stone閱讀 1,244評論 1 13
  • 閉包(closure)是Javascript語言的一個難點,也是它的特色,很多高級應用都要依靠閉包實現(xiàn)。 一、變量...
    zock閱讀 1,119評論 2 6
  • 今天孩子的學生群老師曬了幾篇日記,有一篇寫關于買干脆面的日記,我看完之后心里想這是誰家孩子,日記怎么寫的這么好,還...
    杏花林閱讀 242評論 1 0

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