JavaScript中的閉包并不難理解

一、閉包(Closures)的定義

描述閉包定義之前需要先了解一個(gè)學(xué)術(shù)名詞--(free variable)自由變量纫骑,網(wǎng)絡(luò)上的解釋是:一些被某個(gè)方法使用的變量,且這些變量既不是方法中定義的變量也不是方法的參數(shù)隔显。


官方對閉包的描述也是非常的簡單项鬼,就一句話:

閉包是使用自由變量的方法。

1.1 如何創(chuàng)建一個(gè)閉包

根據(jù)閉包的定義耻陕,相信很難有人能一下子理解它的含義拙徽,下面就使用代碼來說明:

function a() {
    var n = 1;
    function b() {
        console.log(n++);
    }
}

觀察以上代碼可以發(fā)現(xiàn)以下特點(diǎn):

  • 方法a中內(nèi)嵌了方法b
  • 方法b使用了方法a中的變量

其實(shí)當(dāng)JavaScript解釋器執(zhí)行完這段代碼時(shí),并沒有產(chǎn)生閉包诗宣,為什么呢膘怕?雖然我們可以看到方法b使用外部的變量n,但是此時(shí)a中的邏輯并沒有執(zhí)行召庞,不管是n還是b岛心,這些只是方法a的描述信息而已,此時(shí)JavaScript環(huán)境中并沒有方法b存在篮灼。那何時(shí)才能產(chǎn)生閉包呢忘古,答案是:當(dāng)JavaScript解釋器定義方法b的時(shí)候。當(dāng)我們執(zhí)行a();時(shí)诅诱,a中的語句得以執(zhí)行髓堪,首先創(chuàng)建了變量n,然后定義了方法b,而定義方法b時(shí)需要外部的變量n旦袋,此時(shí)才符合閉包定義的描述骤菠,這時(shí)方法b才是一個(gè)閉包。

二疤孕、閉包的應(yīng)用

2.1 面向?qū)ο蟮乃季S

由上例可以看出商乎,一個(gè)閉包由兩部分組成:自由變量和使用自由變量的方法;面向?qū)ο蟮幕驹鼐褪菍ο蠹婪В瑢ο蠛袑傩院头椒钠荩划?dāng)我們把閉包看做一個(gè)對象時(shí),自由變量就是屬性专控,而使用自有變量的方法就是方法抹凳;由于單一的閉包指的是使用自由變量的方法,終歸還是一個(gè)方法伦腐,所以這種對象本質(zhì)還是一個(gè)方法赢底。

比如有這樣一個(gè)需求:小明今年10歲,小王今年20歲柏蘑,小李今年30歲幸冻,請問5年后,他們分別多少歲咳焚?使用面向?qū)ο蟮乃枷刖帉懘a如下:

// 從閉包的角度看洽损,這里我們相當(dāng)于定義了一個(gè)類,它的屬性是:name革半,方法是:future()
function man(name, age) {
    function future() {
        console.log(name + "未來的年齡:" + (age + 5));
    }
    return future;
};

// 創(chuàng)建三個(gè)對象
// xiaomingObj對象的屬性:name = "xiaoming"碑定,方法:future()
var xiaomingObj = man("xiaoming", 10);
// 打印:xiaoming未來的年齡:15
xiaomingObj();

// xiaowangObj 對象的屬性:name = "xiaowang"又官;方法:future()
var xiaowangObj = man("xiaowang", 20);
// 打友恿酢:xiaowang未來的年齡:15
xiaowangObj();

// xiaoliObj對象的屬性:name = "xiaoli";方法:future()
var xiaoliObj = man("xiaoli", 30);
// 打恿础:xiaoli未來的年齡:15
xiaoliObj();

2.2 封裝私有變量和方法

這是閉包最重要的用途了访娶,因?yàn)殚]包使用的自由變量對外部不可見,所以可以起到私有化的作用觉阅,只向外提供必要的接口崖疤,封裝內(nèi)部邏輯。正是因?yàn)橛辛碎]包典勇,才為JavaScript的模塊化編程奠定了基礎(chǔ)劫哼。

封裝私有變量和方法示例:

var human = (function() {
    // 私有變量
    var name = "林";

    // 私有方法
    var think = function() {
        // 心想還是讓別人叫我小林吧
        return "小" + name;
    };

    // 提供的外部接口
    return {
        speak : function() {
            console.log("你好,可以叫我" + think());
        }
    };
})();

// 打痈铙稀:你好权烧,可以叫我小林
human.speak();

代碼說明:

外層是一個(gè)匿名方法:function(){...}眯亦,通過立即執(zhí)行的方式(用括號(hào)包裹起來作為方法表達(dá)式,并使用()立即執(zhí)行)創(chuàng)建了一個(gè)閉包:speak及其引用的think般码;外部的human無法直接訪問name與think妻率,只能訪問對外開放的speak,從而達(dá)到封裝的效果板祝。

三宫静、循環(huán)中的誤區(qū)

對于新手來說,使用閉包經(jīng)常會(huì)犯的一個(gè)錯(cuò)誤是:在循環(huán)中創(chuàng)建閉包券时。請分析以下代碼:

function a() {
    var b = null;
    for (var i = 0; i < 3; i++) {
        if (i === 1) {
            b = function() {
                console.log(i);
            }   
        }
    }
    return b;
}

// 你覺得會(huì)打印什么孤里?
a()();

如果你覺得會(huì)打印出1,那恭喜你進(jìn)坑了橘洞;說明你還沒有完全理解閉包捌袜,正確的答案是3,為什么呢炸枣?因?yàn)閳?zhí)行了a()后虏等,創(chuàng)建的閉包所包含的自由變量是i,當(dāng)a()執(zhí)行完畢后适肠,i被更新為3霍衫,此時(shí)b還沒有被調(diào)用,當(dāng)執(zhí)行a()()時(shí)迂猴,b才被調(diào)用慕淡,所以打印出了3背伴。

四沸毁、性能考慮

閉包對性能和內(nèi)存都有相對較高的消耗,除非特殊場景的需要傻寂,不要隨便使用閉包息尺;閉包相當(dāng)于通過方法來定義方法,每次創(chuàng)建閉包時(shí)都會(huì)對方法重新定義疾掰;當(dāng)閉包被外部引用時(shí)搂誉,由于閉包內(nèi)的自由變量無法釋放,也會(huì)導(dǎo)致內(nèi)存無法釋放静檬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末炭懊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子拂檩,更是在濱河造成了極大的恐慌侮腹,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稻励,死亡現(xiàn)場離奇詭異父阻,居然都是意外死亡愈涩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門加矛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來履婉,“玉大人,你說我怎么就攤上這事斟览』偻龋” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵趣惠,是天一觀的道長狸棍。 經(jīng)常有香客問我,道長味悄,這世上最難降的妖魔是什么草戈? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮侍瑟,結(jié)果婚禮上唐片,老公的妹妹穿的比我還像新娘。我一直安慰自己涨颜,他們只是感情好费韭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著庭瑰,像睡著了一般星持。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上弹灭,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天督暂,我揣著相機(jī)與錄音,去河邊找鬼穷吮。 笑死逻翁,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的捡鱼。 我是一名探鬼主播八回,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼驾诈!你這毒婦竟也來了缠诅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤乍迄,失蹤者是張志新(化名)和其女友劉穎管引,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體就乓,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡汉匙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年拱烁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片噩翠。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡戏自,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出伤锚,到底是詐尸還是另有隱情擅笔,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布屯援,位于F島的核電站猛们,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏狞洋。R本人自食惡果不足惜弯淘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吉懊。 院中可真熱鬧庐橙,春花似錦、人聲如沸借嗽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恶导。三九已至浆竭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惨寿,已是汗流浹背邦泄。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缤沦,地道東北人虎韵。 一個(gè)月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓易稠,卻偏偏與公主長得像缸废,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子驶社,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 閉包(closure)是Javascript語言的一個(gè)難點(diǎn)企量,也是它的特色,很多高級(jí)應(yīng)用都要依靠閉包實(shí)現(xiàn)亡电。 一届巩、變量...
    zouCode閱讀 1,271評論 0 13
  • 閉包(closure)是Javascript語言的一個(gè)難點(diǎn),也是它的特色份乒,很多高級(jí)應(yīng)用都要依靠閉包實(shí)現(xiàn)恕汇。 一腕唧、變量...
    zock閱讀 1,075評論 2 6
  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 10,958評論 6 13
  • 倚窗而望 雨絲牽線而下 秋意涼然 不覺打了寒顫 端起一杯菊花冰糖茶 苦澀帶著甜甜的味道滲入舌下 多日的身體不適 讓...
    田萍閱讀 327評論 0 7
  • 「我告訴你,我是善良的瘾英,但我不僅僅是善良的枣接,當(dāng)你那副對待我的嘴臉太過難看,老娘不介意把身上柔軟的毛皮收起來缺谴,然后穿...
    小驢驢驢閱讀 817評論 1 18