JavaScript 閉包

閉包是什么

閉包就是一個擁有變量和綁定了這些變量的環(huán)境的表達式(通常是一個函數(shù)),是一個有權(quán)訪問其外部作用域中變量的函數(shù)观蓄。最常見的方式就是在某函數(shù)內(nèi)部創(chuàng)建一個函數(shù)。

  • 優(yōu)點
    能夠讀取函數(shù)內(nèi)部的變量祠墅,并且讓這些變量的值始終保存在內(nèi)存中侮穿。使用閉包和匿名自執(zhí)行函數(shù)實現(xiàn)模塊化。
  • 缺點
    1.既然不釋放內(nèi)存毁嗦,則必然會對內(nèi)存的消耗很大亲茅,造成頁面訪問的性能問題
    2.閉包會改變父函數(shù)的私有屬性,在你不經(jīng)意的時候

一個經(jīng)典的例子

function test(){  
 for(var i = 0; i < 10 ; i++){  
     setTimeout(function(){  
        console.log(i)  
    }, 0);  
  }  
}  
test();

我相信大家都會瞬間給出答案:輸出是個10狗准,原因如下:

  • test()執(zhí)行時會創(chuàng)建一個運行時期的上下文克锣,而setTimeout內(nèi)部的函數(shù)會放在for循環(huán)隊列之后,等到for循環(huán)執(zhí)行完之后才開始執(zhí)行腔长。
  • function(){console.log(i)}執(zhí)行時首先會尋找函數(shù)內(nèi)部的變量i袭祟。此時找不到i,再尋找test中的i
  • (閉包的概念:訪問函數(shù)外的變量饼酿,這些變量只有等到閉包不使用才會被銷毀)此時的i值已經(jīng)變?yōu)榱?0榕酒,所以十次執(zhí)行都會輸出10胚膊。

解決這個問題的方法如下

function test(){  
    for(var i = 0; i < 10 ; i++){  
     (function(li){  
        setTimeout(function(){  
            console.log(li)  
         }, 0);  
     })(i);  
    }  
}  
test(); 

再舉一個例子

function f1(){  
 var n=999;  
 nAdd=function(){n+=1}//定義了一個全局變量故俐,相當于setter,方便在函數(shù)外部對函數(shù)內(nèi)部的變量進行操作紊婉,不是本文要說明的重點  
 function f2(){  
  console.log(n);  
 }  
 return f2;  
}  
var result=f1();  
result();   //返回內(nèi)部函數(shù)f2,f2訪問外部函數(shù)f1的局部變量n药版,999  
nAdd();     // f1函數(shù)聲明后,產(chǎn)生window.nAdd
result();   // 1000喻犁,可見變量n保存在了內(nèi)存中槽片;  
var result2 = f1();  
result2();//999 這里的值為什么不是1000呢何缓?帶著疑問往下看

一個函數(shù),當沒有依賴關(guān)系存在時还栓,就會有被垃圾回收機制回收的可能碌廓,但是如果像上文案例f1()那樣,將內(nèi)部函數(shù)(f2)作為返回值賦值給一個全局變量剩盒,則會改變這種潛在的關(guān)系谷婆。這種即使離開函數(shù)作用域仍能通過引用來調(diào)用內(nèi)部函數(shù)(或變量)的事實,意味著辽聊,只要存在調(diào)用內(nèi)部函數(shù)的可能纪挎,JavaScript就需要保留被該內(nèi)部函數(shù)引用的函數(shù)(即所謂的外部函數(shù))

JavaScript運行時會跟蹤引用這個內(nèi)部函數(shù)的所有變量,知道最后一個變量廢棄跟匆,JavaScript垃圾回收機制才能釋放對應的空間(將內(nèi)部函數(shù)置為null)

根據(jù)上面的論述,我們來分析一下第二個例子:

  • f1()函數(shù)的返回值是內(nèi)部函數(shù)f2()并將返回值賦值給了全局變量result
  • f2()保存有f1()的的依賴關(guān)系异袄,導致f2()始終在內(nèi)存中未被清除,可以在外部訪問到f1()中的變量
  • result2()執(zhí)行后打印了999玛臂,而不是1000烤蜕。是因為創(chuàng)建新的封閉環(huán)境,本質(zhì)上是創(chuàng)建了一個新的對象垢揩,而閉包就是這個對象的實例方法

小測試

第一題:

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

答案是:'The Window'

這樣理解 var fun = object.getNameFunc();這個返回的是一個function

fun = function(){
    return this.name;
}

此時玖绿,fun中的this指向是window,所以this.name是The window

這道題是典型的閉包沒閉上~要么用聰明的that來解決叁巨,要么使用 真·閉包

// 聰明的that
var name = "The Window";
var object = {
  name : "My Object",
  getNameFunc : function(){
    var that = this;//這里的that現(xiàn)在是相當于object這個對象了
    return function(){
      return that.name;//所以這里面輸出的是object.name,也就是"My Object"
    };
  }
};
alert(object.getNameFunc()());

// 真·閉包術(shù)
var name = "The Window";
var object = {
    name : "My Object",
    getNameFunc : (function(){
      return function(){
        return this.name;
     };
    })()
};
alert(object.getNameFunc()); //My Object

推薦文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斑匪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子锋勺,更是在濱河造成了極大的恐慌蚀瘸,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件庶橱,死亡現(xiàn)場離奇詭異贮勃,居然都是意外死亡,警方通過查閱死者的電腦和手機苏章,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門寂嘉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人枫绅,你說我怎么就攤上這事泉孩。” “怎么了并淋?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵寓搬,是天一觀的道長。 經(jīng)常有香客問我县耽,道長句喷,這世上最難降的妖魔是什么镣典? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮唾琼,結(jié)果婚禮上兄春,老公的妹妹穿的比我還像新娘。我一直安慰自己锡溯,他們只是感情好神郊,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著趾唱,像睡著了一般涌乳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上甜癞,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天夕晓,我揣著相機與錄音,去河邊找鬼悠咱。 笑死蒸辆,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的析既。 我是一名探鬼主播躬贡,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼眼坏!你這毒婦竟也來了拂玻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤宰译,失蹤者是張志新(化名)和其女友劉穎檐蚜,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沿侈,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡闯第,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了缀拭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咳短。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蛛淋,靈堂內(nèi)的尸體忽然破棺而出咙好,到底是詐尸還是另有隱情,我是刑警寧澤铣鹏,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布敷扫,位于F島的核電站哀蘑,受9級特大地震影響诚卸,放射性物質(zhì)發(fā)生泄漏葵第。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一合溺、第九天 我趴在偏房一處隱蔽的房頂上張望卒密。 院中可真熱鬧,春花似錦棠赛、人聲如沸哮奇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鼎俘。三九已至,卻和暖如春辩涝,著一層夾襖步出監(jiān)牢的瞬間贸伐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工怔揩, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留捉邢,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓商膊,卻偏偏與公主長得像伏伐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子晕拆,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

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

  • 閉包(closure)是Javascript語言的一個難點藐翎,也是它的特色,很多高級應用都要依靠閉包實現(xiàn)实幕。 一阱高、變量...
    zouCode閱讀 1,270評論 0 13
  • Javascript閉包的定義非常晦澀——閉包茬缩,是指語法域位于某個特定的區(qū)域赤惊,具有持續(xù)參照(讀寫)位于該區(qū)域內(nèi)自身...
    LiLi原上草閱讀 415評論 2 3
  • 前言 這篇文章使用有效的javascript代碼向程序員們解釋了閉包,大牛和功能型程序員請自行忽略凰锡。 基礎篇 閉包...
    kiaizi閱讀 355評論 0 7
  • 一未舟、閉包有什么用 1、能夠在函數(shù)外部引用函數(shù)內(nèi)部的變量(變量作用域)掂为; 2裕膀、讓變量的值始終保持在內(nèi)存中(垃圾回收機...
    你這個人真的是閱讀 342評論 0 1
  • 是什么束縛了我們的想象昼扛?在陪伴孩子畫畫中,我漸漸找到一點線索。 陪著孩子一起畫畫抄谐,看著孩子幾只筆來回交換渺鹦,揮毫潑...
    文哥解課閱讀 222評論 0 1