閉包之我的理解

閉包是javascript的一個(gè)難點(diǎn)厌殉,也是一個(gè)重點(diǎn),很多高級應(yīng)用都需要用到閉包。在學(xué)習(xí)閉包的過程中看了不少書和大牛的博客适肠,下面來說說我對閉包的理解和看法。

函數(shù)

要說閉包就不得不先說一下函數(shù)候引,這個(gè)javascript的中流砥柱侯养。
眾所周知在ES6之前js都沒有class這個(gè)關(guān)鍵字,一切的面向?qū)ο蠖际峭ㄟ^function模擬的澄干。

一個(gè)簡單到不能再簡單的例子:函數(shù)內(nèi)部可以訪問外部的變量(全局變量)逛揩。

var n=100;
function f1()
{
    console.log(n);
}
f1();//100

而外部卻不能訪問函數(shù)內(nèi)的局部變量。

function f1()
{
    var n=100;
}
console.log(n);//n is not defined

那么問題來了麸俘,如果我想訪問函數(shù)內(nèi)的局部變量怎么辦辩稽?一種解決辦法就是使用閉包。
什么是閉包从媚?我個(gè)人認(rèn)為函數(shù)中的函數(shù)就是閉包逞泄,有點(diǎn)像java的內(nèi)部類,既然函數(shù)可以訪問外部變量,那么函數(shù)中的函數(shù)也可以訪問外層函數(shù)的變量喷众,這個(gè)內(nèi)層函數(shù)就是閉包各谚。

function f1()
{
    var n=100;
    function f2()
    {
        console.log(n);
    }
    f2();
}
f1();//100

上述寫法比較麻煩,因此可以把f2作為一個(gè)返回值返回給f1到千。

function f1()
{
    var n=100;
    function f2()
    {
        console.log(n);
    }
    return f2;
}
f1()();//100
//相當(dāng)于var f=f1();f();

下面來看一個(gè)問題:這里有5個(gè)li昌渤,名字是0到4,我希望我點(diǎn)擊0的時(shí)候在控制臺輸出0憔四,點(diǎn)擊1的時(shí)候在控制臺輸出1愈涩,以此類推。

var lis=document.getElementsByTagName("li");
for(var i=0;i<lis.length;i++)
{
    lis[i].onclick=function()
    {
        console.log(i);
    }
}

奇怪的事情發(fā)生了加矛,無論我點(diǎn)擊哪一個(gè)在控制臺輸出的都是5履婉。
這是為什么呢?
仔細(xì)觀察斟览,我為每個(gè)li創(chuàng)建了一個(gè)匿名函數(shù)毁腿,匿名函數(shù)形成了閉包,它們都在引用外部的i苛茂,當(dāng)i改變時(shí)已烤,自然所有匿名函數(shù)里面的i都改變了。用幾張圖來說明妓羊。




當(dāng)i增加到5的時(shí)候不再滿足循環(huán)條件胯究,由于五個(gè)匿名函數(shù)都是引用同一個(gè)i,所以它們打印出來的都是5躁绸。

既然它們是引用同一個(gè)i裕循,那么只需為每一個(gè)i創(chuàng)建一個(gè)備份:

var lis=document.getElementsByTagName("li");
for(var i=0;i<lis.length;i++)
{
    lis[i].onclick=function(num)
    {
        return function()
        {
            console.log(num);
        }
    }(i)
}

這里在匿名函數(shù)接收一個(gè)參數(shù)并且立即執(zhí)行,匿名函數(shù)內(nèi)部又創(chuàng)建了一個(gè)函數(shù)負(fù)責(zé)把這個(gè)參數(shù)返回給匿名函數(shù)净刮,由于是按值傳遞的剥哑,所以相當(dāng)于給i做了一個(gè)備份。就算i一直在改變淹父,而每個(gè)匿名函數(shù)的num是固定的株婴。

閉包中的this

在閉包中使用this會出現(xiàn)一些問題,在全局函數(shù)中this指向的是window暑认,當(dāng)函數(shù)以方法被調(diào)用時(shí)困介,this就指向這個(gè)對象。但是蘸际,匿名函數(shù)的執(zhí)行環(huán)境具有全局性座哩,this一般指向window。參考紅寶石書中的一個(gè)經(jīng)典的問題:

var name="The Window";
var object={
    name:"My Object",
    getNameFunc:function(){
        return function(){
           return this.name;
        };
    }
};
alert(object.getNameFunc()());//"The Window"

內(nèi)部函數(shù)在搜索this的時(shí)候只會搜到其活動(dòng)對象為止捡鱼,由于匿名函數(shù)的執(zhí)行環(huán)境具有全局性八回,因此當(dāng)前的活動(dòng)對象就是window。

可以通過改變當(dāng)前的活動(dòng)對象來改變this的指向:

var name="The Window";
var object={
    name:"My Object",
    getNameFunc:function(){
        var that=this;
        return function(){
            return that.name;
        };
    }
};
alert(object.getNameFunc()());//"My Object"

這里把this對象賦值給了一個(gè)that變量驾诈,因此當(dāng)前的活動(dòng)對象就從window變成了object缠诅。

閉包引發(fā)的問題

閉包雖好,但是也引發(fā)了一系列問題乍迄,尤其是內(nèi)存泄漏管引。js的垃圾回收機(jī)制是引用計(jì)數(shù)的,當(dāng)一個(gè)變量不再使用的時(shí)候(引用計(jì)數(shù)為0)垃圾回收機(jī)制就會把它清理掉闯两。而閉包的存在會導(dǎo)致引用數(shù)至少為1褥伴。

function f()
{
   var myDiv=document.getElementById("Div1");
   myDiv.onclick=function()
   {
        console.log(myDiv.id);
   };
}

上述代碼中,函數(shù)f需要等myDiv清除后才能被清除漾狼,而myDiv由于匿名函數(shù)的存在重慢,它的引用數(shù)至少為1,因此它所占用的內(nèi)存永遠(yuǎn)不會被回收逊躁。

解決辦法:

function f()
{
   var myDiv=document.getElementById("Div1");
   var id=myDiv.id
   myDiv.onclick=function()
   {
        console.log(id);
   };
   myDiv=null;
}

把myDiv.id保存在一個(gè)變量中似踱,并且在閉包中引用這個(gè)變量,這樣就與myDiv沒有關(guān)系了稽煤。但是閉包會引用包含函數(shù)的整個(gè)活動(dòng)對象核芽,因此必須把myDiv設(shè)為null來解除對它的引用,確保垃圾回收機(jī)制能夠把資源回收酵熙。

使用閉包應(yīng)該注意的問題:閉包雖然好轧简,但是在實(shí)際應(yīng)用中盡量減少 閉包的使用,并且為了防止內(nèi)存泄漏匾二,要時(shí)刻記得在閉包完后清除它的局部變量哮独。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市察藐,隨后出現(xiàn)的幾起案子借嗽,更是在濱河造成了極大的恐慌,老刑警劉巖转培,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恶导,死亡現(xiàn)場離奇詭異,居然都是意外死亡浸须,警方通過查閱死者的電腦和手機(jī)惨寿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來删窒,“玉大人裂垦,你說我怎么就攤上這事〖∷鳎” “怎么了蕉拢?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我晕换,道長午乓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任闸准,我火速辦了婚禮益愈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘夷家。我一直安慰自己蒸其,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布库快。 她就那樣靜靜地躺著摸袁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪义屏。 梳的紋絲不亂的頭發(fā)上但惶,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機(jī)與錄音湿蛔,去河邊找鬼膀曾。 笑死,一個(gè)胖子當(dāng)著我的面吹牛阳啥,可吹牛的內(nèi)容都是我干的添谊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼察迟,長吁一口氣:“原來是場噩夢啊……” “哼斩狱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起扎瓶,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤所踊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后概荷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體秕岛,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年误证,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了继薛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,727評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡愈捅,死狀恐怖遏考,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蓝谨,我是刑警寧澤灌具,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布青团,位于F島的核電站,受9級特大地震影響咖楣,放射性物質(zhì)發(fā)生泄漏督笆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一截歉、第九天 我趴在偏房一處隱蔽的房頂上張望胖腾。 院中可真熱鬧烟零,春花似錦瘪松、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至墅诡,卻和暖如春壳嚎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背末早。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工烟馅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人然磷。 一個(gè)月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓郑趁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親姿搜。 傳聞我的和親對象是個(gè)殘疾皇子寡润,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評論 2 354

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

  • 閉包(closure)是Javascript語言的一個(gè)難點(diǎn),也是它的特色舅柜,很多高級應(yīng)用都要依靠閉包實(shí)現(xiàn)梭纹。 一、變量...
    zock閱讀 1,075評論 2 6
  • 閉包: 官方”的解釋是:閉包是一個(gè)擁有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個(gè)函數(shù))致份,因而這些變量也是該...
    小裁縫sun閱讀 616評論 0 5
  • 20歲生日那天氮块,收到來自世界上最愛我的男人的一封長長的信和一首矯情的詩瞬沦,在信里他叫我寶貝,在詩里他稱我親親雇锡,在我2...
    橙子橙子薇閱讀 497評論 0 1
  • 1逛钻,九月的第一個(gè)周一,2017年還有一百來天锰提。制定的計(jì)劃大的方向沒有變動(dòng)曙痘,有微小的在調(diào)整芳悲。前段時(shí)間讀到一個(gè)故事,說...
    玄弋閱讀 360評論 0 3
  • 時(shí)間:2016.3.11 書籍: 進(jìn)度:10-17 感悟:在職場中边坤,很多關(guān)系要么過于緊張而令人難以忍受名扛,要么緊張不...
    24K超超老師閱讀 175評論 0 0