JavaScript對閉包的理解
- 前言
- 關于閉包
- 1.是什么?
- 2.優缺點?
- 3.怎么用?(以累加器舉例)
- 引入變數的生命周期
- 于是我們用上閉包
- 總結
前言
本文是作者學習階段對閉包的理解,主要介紹了閉包的基礎知識點和對知識點的理解,
本文排版約定
Q — 問題
A — 回答
關于閉包
1.是什么?
《你不知道的JavaScript》里的定義為:
當函式可以記住并訪問所在的詞法作用域時,就產生了閉包,即使函式是在當前詞法作用域之外執行,
2.優缺點?
優點
- 實作封裝,屬性私有化, 在自己的函式作用域內,實作內部成員變數,提供function介面,
- 保護作用域不被釋放,成員變數被快取起來具有記憶性,
- 模塊開發,防止污染全域變數,
缺點
- 閉包會導致作用域鏈不釋放,造成記憶體泄漏
3.怎么用?(以累加器舉例)
引入變數的生命周期
code - 1:
var x = 0;
function fn1() {
return ++x;
}
console.log(fn1());
console.log(fn1());
//輸出:
//1
//2
code - 2:
function fn2() {
var x = 0;
return ++x;
}
console.log(fn2());
console.log(fn2());
//輸出:
//1
//1
Q1:為什么輸出的結果不同?
A1:我們知道JS是運行在瀏覽器,瀏覽器引擎有垃圾回收器,
fn1()和fn2()在完成自己的"任務"之后,都被回收釋放了,code -1 中的變數x為全域變數,快取仍然存在,不會被回收;但code-2中的變數x定義在fn2()中,為區域變數,所以x一并被回收,
code-2代碼中的fn2()被重復呼叫時,x一直在被重復定義并賦值為0,沒有被快取下來,
Q2:code-1實作了累加計數,為什么還要使用閉包這個概念,換言之code-1有什么缺陷?
A2:我們知道,在一個專案中需要使用到很多變數名,code-1將變數定義在全域范圍內(這沒有錯),造成了全域變數的污染;并且變數x不常使用的話,閑置在記憶體中,浪費記憶體空間,
于是我們用上閉包
code - 2.1:
//這里用到了自執行函式(function(){})()
var add = (function () {
var x = 0;
function doAdd() {return x += 1;}
return doAdd;
})();
console.log(add());
console.log(add());
console.log(add());
//輸出:
//1
//2
//3
此時,變數x就只作用于匿名函式所在的那個作用域,不會對全域變數造成污染,當code - 2.1執行完第一個console.log(add());垃圾回收器并不會對add進行回收釋放,因為doAdd函式已經被保存到外部,作用域仍然存在,
總而言之累加器受匿名函式的作用域保護,只能通過 add 方法修改,
這也解釋了閉包的缺點,如果寫了太多的閉包,就會占用大量的記憶體,從而導致記憶體泄漏,閉包需要手動記憶體釋放,讓參考 add = null;即可
總結
-
通過案例學過 java 的朋友就不難想到 閉包和"類"非常的相似,
定義在函式內部的變數 -> 類中的成員變數
定義在函式中的方法 -> 類中的成員方法
好比物件,通過封裝來讓變數私有化,提供函式來訪問成員變數, -
最后,我理解得出閉包像是一種保護機制;閉包形成一個不銷毀的堆疊環境,用來保護內部函式,成員屬性不受外界的干擾,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/279277.html
標籤:其他
下一篇:移動端開發
