理解Javascript閉包
閉包是ECMAScript一個(gè)很重要的特征,但是卻很難用合適的定義來描述它。雖然閉包很難清晰地描述,但是,卻很容易創(chuàng)建,或者說,不小心創(chuàng)建。然而,閉包的存在其實(shí)是有一定的潛在問題的。為了避免“不小心”地創(chuàng)建閉包,以及更好地利用閉包的優(yōu)點(diǎn),有必要理解閉包的機(jī)制。
閉包的定義
關(guān)于閉包,有太多的定義,特別是有一些定義非常抽象,象這個(gè):
A "closure" is an expression (typically a function) that can have free variables together with an environment that binds those variables.
大致是說閉包是一個(gè)表達(dá)式,擁有一些自由變量及綁定這些變量的執(zhí)行環(huán)境。這種定義太書面化,反而難以理解。
還有另一個(gè)定義:
所有函數(shù)都是閉包。這個(gè)定義給我很大的迷惑,換句話說,由于Javascript沒有塊級作用域,因此閉包一般指的是函數(shù)(想不出除了函數(shù)以外還有哪些方式可以構(gòu)成閉包)。
這里不想太多討論函數(shù)與閉包的關(guān)系,下面給出我認(rèn)為比較容易理解的定義吧。
首先,閉包的存在是基于作用域鏈。由于作用域鏈的機(jī)制,所有函數(shù)(即使全局函數(shù))都能引用上下文執(zhí)行環(huán)境中的變量(即free variables)。
其次,閉包內(nèi)部必須有free variables。順便說下兩種變量1. Local variables (bound variables) 2. Non-local variables (free variables)
最后,在其上下文環(huán)境結(jié)束后仍然存在。即內(nèi)部函數(shù)擁有比它的外部函數(shù)更長的生命周期。
關(guān)于閉包定義的解析
關(guān)于閉包定義的兩點(diǎn),一直在考慮是不是必須同時(shí)滿足。
首先,如果閉包內(nèi)部沒有free variables,即是說它沒有訪問外部的變量,那么就失去了閉包的意義。(除非通過其他閉包改變了行為)因此,我認(rèn)為free variables是必要條件。
其次,如果函數(shù)內(nèi)部存在free variables,但是當(dāng)其上下文環(huán)境銷毀后,它也跟著銷毀。可以想象內(nèi)部函數(shù),雖然訪問了其外部函數(shù)變量,但是當(dāng)外部函數(shù)執(zhí)行完后也隨之回收。這種情況下,閉包的討論也沒有意義。
來看兩個(gè)例子:
var objectA = (function() {
var localA = "localA";
innerFn();
// 單純的內(nèi)部函數(shù)調(diào)用
function innerFn() {
localA = "innerChange";
}
return {
getLocalA : function() {
return "empty";
}
};
})();
objectA.getLocalA();
objectA.getLocalA = function() {
return localA;
};
//console.log(objectA.getLocalA()); //error: localA is not defined
var objectB = (function() {
var localB = "localB";
return {
getLocalB : function() {
return "empty";
},
updateGetLocalB : function() {
this.getLocalB = function() {
return localB;
};
},
updateLocalB : function() {
localB = "changeLocalB";
}
};
})();
console.log(objectB.getLocalB()); // empty
// 通過其他閉包改變
objectB.updateGetLocalB();
console.log(objectB.getLocalB()); // localB
objectB.updateLocalB();
console.log(objectB.getLocalB()); // changeLocalB
閉包的優(yōu)點(diǎn)和缺點(diǎn)
閉包的優(yōu)點(diǎn)是閉包內(nèi)部可以訪問到定義它們的外部函數(shù)的參數(shù)和變量(除了this和arguments)。
閉包主要的問題便是它會(huì)保存包含它的函數(shù)的作用域,因此比一般函數(shù)占用更多的內(nèi)存空間,因此不宜過度使用閉包。
閉包的應(yīng)用
閉包最基本的應(yīng)用場景便是通過保護(hù)內(nèi)部變量從而實(shí)現(xiàn)私有,比如模塊模式。
相關(guān)文章
vue2.x的深入學(xué)習(xí)--關(guān)于h函數(shù)的說明
下面小編就為大家分享一篇基于h函數(shù)詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-08-08WEB泡泡堂2.0(圖形界面+電腦對玩)(javascript)
WEB泡泡堂2.0(圖形界面+電腦對玩)(javascript)2007-01-01js基于setTimeout與setInterval實(shí)現(xiàn)多線程
這篇文章主要介紹了js基于setTimeout與setInterval實(shí)現(xiàn)多線程的方法,分析了多線程的原理與javascript模擬實(shí)現(xiàn)多線程的相關(guān)技巧,需要的朋友可以參考下2016-06-06微信小程序如何調(diào)用新聞接口實(shí)現(xiàn)列表循環(huán)
這篇文章主要介紹了微信小程序如何調(diào)用新聞接口實(shí)現(xiàn)列表循環(huán),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07jquery實(shí)現(xiàn)瀑布流效果 jquery下拉加載新數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了jquery實(shí)現(xiàn)瀑布流效果,下拉加載新數(shù)據(jù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12JavaScript 斐波那契數(shù)列 倒序輸出 輸出100以內(nèi)的質(zhì)數(shù)代碼實(shí)例
這篇文章主要介紹了JavaScript 斐波那契數(shù)列 倒序輸出 輸出100以內(nèi)的質(zhì)數(shù)代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-0924行JavaScript代碼實(shí)現(xiàn)Redux的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于如何利用24行JavaScript代碼實(shí)現(xiàn)Redux的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用JavaScript具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11關(guān)于javascript sort()排序你可能忽略的一點(diǎn)理解
最近在研究Javascript發(fā)現(xiàn)了其中一些之前忽略的問題,所以想著總結(jié)分享出來,下面這篇文章主要給大家介紹了關(guān)于javascript sort()排序你可能忽略的一點(diǎn)理解,文中介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧。2017-07-07