理解js閉包

如果你學(xué)JavaScript已經(jīng)有一段時(shí)間了,你一定聽(tīng)過(guò)js閉包。這也是前端面試非常喜歡問(wèn)的問(wèn)題呼股,所以理解js閉包對(duì)學(xué)習(xí)JavaScript至關(guān)重要。我曾經(jīng)多次理解js閉包画恰,但是每次我覺(jué)得我理解的時(shí)候彭谁,都會(huì)被之后的某些坑證明我根本沒(méi)有理解,最近在學(xué)習(xí)vue.js,所以想繼續(xù)扎實(shí)下原生js阐枣,又遇到了閉包马靠,所以借此機(jī)會(huì)總結(jié)一下對(duì)js閉包的理解。

初識(shí)閉包

我并不是從教材開(kāi)始JavaScript的學(xué)習(xí)的蔼两,所以一開(kāi)始并不知道有閉包這一概念甩鳄。而之所以開(kāi)始了解閉包是因?yàn)閿]碼中一個(gè)很常見(jiàn)的場(chǎng)景:如給列表的每一項(xiàng)都加一個(gè)根據(jù)index的事件,所以很自然的我們會(huì)這么寫(xiě)

for(var i=0;i<items.length;i++){
      items[i].onclick=function(){
            console.log(i);
      }
}

然而额划,我發(fā)現(xiàn)結(jié)果并非我想象的那樣妙啃,i永遠(yuǎn)都是items.length,然后我問(wèn)別人也好,百度也罷俊戳,總是聽(tīng)到見(jiàn)到閉包這個(gè)詞揖赴,然后開(kāi)始去理解它。

理解閉包

1.閉包概念(出自JavaScript高級(jí)程序設(shè)計(jì))閉包是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)
主謂賓:閉包是函數(shù)
定(什么樣的函數(shù)):有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中變量的函數(shù)
2.理解閉包所需的知識(shí)
1.JavaScript語(yǔ)言的作用域(ES6之前)沒(méi)有塊級(jí)作用域抑胎,只有全局作用域與函數(shù)作用域燥滑。
2.執(zhí)行環(huán)境、變量對(duì)象阿逃、活動(dòng)對(duì)象铭拧、作用域鏈
執(zhí)行環(huán)境:可以理解為作用域,執(zhí)行環(huán)境定義了變量或函數(shù)有權(quán)訪問(wèn)的其他數(shù)據(jù)恃锉,決定了它們各自的行為搀菩。
變量對(duì)象:每一個(gè)執(zhí)行環(huán)境都有一個(gè)關(guān)聯(lián)的變量對(duì)象,用于保存該環(huán)境中定義的所有變量和函數(shù)破托。例如與全局執(zhí)行環(huán)境關(guān)聯(lián)的便是全局變量對(duì)象肪跋,所有全局變量與方法都會(huì)添加到該對(duì)象上。如在瀏覽器環(huán)境下土砂,全局對(duì)象即window對(duì)象州既。
活動(dòng)對(duì)象:當(dāng)執(zhí)行環(huán)境是函數(shù)時(shí)谜洽,所關(guān)聯(lián)的變量對(duì)象。
作用域鏈:顧名思義易桃,即多個(gè)作用域形成的鏈條褥琐。當(dāng)代碼在環(huán)境中執(zhí)行時(shí),會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈晤郑,用于保證對(duì)執(zhí)行環(huán)境有權(quán)訪問(wèn)的所有變量和函數(shù)的有序訪問(wèn)敌呈。
看概念可能和容易糊涂,但通過(guò)代碼很好理解造寝。

var color="red";
function changeColor(){
    var anotherColor="blue";
    function swapColor(){
          var tempColor="yellow";
    }
}

上述代碼涉及三個(gè)執(zhí)行環(huán)境磕洪,全局執(zhí)行環(huán)境,changeColor()的執(zhí)行環(huán)境诫龙,swapColor的執(zhí)行環(huán)境析显,但它們之間不是孤立的,而是有關(guān)系的签赃,他們之間相互作用形成了相應(yīng)的作用域鏈谷异。在swaColor()執(zhí)行時(shí)候,它的作用域鏈上有三個(gè)變量對(duì)象锦聊,所以它可以訪問(wèn)所有的變量與函數(shù)歹嘹,但是changeColor執(zhí)行時(shí),所形成的作用域鏈上只有它自己的活動(dòng)對(duì)象與全局對(duì)象孔庭,所以它只能訪問(wèn)自己的變量尺上,函數(shù)和全局變量與函數(shù)。同理圆到,全局執(zhí)行環(huán)境下怎抛,只可以訪問(wèn)全局變量與對(duì)象。
**變量訪問(wèn)是沿著作用域鏈從前到后(全局)進(jìn)行訪問(wèn)的 **
3.js函數(shù)被調(diào)用的細(xì)節(jié)
函數(shù)被調(diào)用時(shí)芽淡,會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境及相應(yīng)的作用域鏈马绝,然后使用arguments和其他命名參數(shù)初始化活動(dòng)對(duì)象。
4.this
在全局函數(shù)中挣菲,this對(duì)象等于window對(duì)象
在函數(shù)作為某對(duì)象方法時(shí)富稻。this等于該對(duì)象
匿名函數(shù)具有全局性
this和arguments是倆特殊的變量,內(nèi)部函數(shù)在搜索這倆個(gè)變量時(shí)己单,只會(huì)搜索到自己的活動(dòng)對(duì)象唉窃。因此永遠(yuǎn)也不可能直接訪問(wèn)外部函數(shù)的這倆變量耙饰。
5.立即執(zhí)行函數(shù)
第一次接觸覺(jué)得還挺玄乎的一個(gè)東西纹笼,而懂了原理只好,就沒(méi)什么東西了苟跪。
函數(shù)定義:function fun1(){}
函數(shù)調(diào)用:fun1();
立即執(zhí)行函數(shù)即將二者結(jié)合起來(lái)廷痘,但是function fun1(){}() 會(huì)報(bào)錯(cuò)蔓涧,因?yàn)槎x無(wú)法調(diào)用,但是表達(dá)式可以笋额,于是上面可以通過(guò)下面這倆種常見(jiàn)的方式結(jié)合
(function fun1(){})() 或者
(function fun1(){}())
6.js函數(shù)傳參是按值傳遞

閉包有何用元暴?怎么用?

1.先來(lái)解釋?zhuān)_(kāi)頭的那段代碼兄猩。茉盏、
i之所以沒(méi)有按照0,1枢冤,2...的順序打印鸠姨,是因?yàn)镴avaScript沒(méi)有塊級(jí)作用域
,所以不同item在調(diào)用綁定的函數(shù)時(shí)淹真,訪問(wèn)的都是同一個(gè)i,而這個(gè)i此時(shí)早已變成了10. 那么如何用閉包實(shí)現(xiàn)我們想要的效果呢讶迁?
模仿一個(gè)塊級(jí)作用域嘍

for(var i=0;i<items.length;i++){
     items[i].onclick=(function(num){
                return function(){
                     console.log(num);
                }
     })(i);
}

這個(gè)return回去的匿名函數(shù),正是我們所創(chuàng)建的閉包核蘸,它可以訪問(wèn)它的上一層作用域中的變量num,而因?yàn)楹瘮?shù)傳參是按值傳參的巍糯,所以針對(duì)每一個(gè)i,在匿名函數(shù)執(zhí)行時(shí),i都會(huì)形成一個(gè)相應(yīng)的副本客扎,而因?yàn)殚]包內(nèi)保持著對(duì)外部變量num的引用祟峦,所以雖然閉包的外部函數(shù)(即匿名立即執(zhí)行函數(shù))已經(jīng)執(zhí)行完畢,但是其作用域鏈仍然在引用該立即執(zhí)行函數(shù)的活動(dòng)對(duì)象虐唠,盡管此時(shí)它的執(zhí)行環(huán)境已經(jīng)被銷(xiāo)毀搀愧。
所以閉包的一個(gè)重要作用就是,讓某些變量的值始終保持在內(nèi)存中疆偿,即模仿塊級(jí)作用域
閉包的另一個(gè)作用就是使得外部作用域可以訪問(wèn)內(nèi)部作用域的變量(根據(jù)上面所講的作用域的知識(shí)咱筛,我們知道默認(rèn)情況下,這是不可能的)但是閉包可以實(shí)現(xiàn)

function fun1(){
  var n=999;
  function fun2(){
      console.log(n);
  }
  return fun2;
}
var r=fun1();
r();

如此杆故,外部便訪問(wèn)到了內(nèi)部變量

注意事項(xiàng)

我們利用閉包模仿塊級(jí)作用域迅箩,將某些變量保存在內(nèi)存中,但也因此會(huì)給我們帶來(lái)一些問(wèn)題处铛。大量使用閉包會(huì)使很多變量保存在內(nèi)存中饲趋,影響網(wǎng)頁(yè)性能,所以使用時(shí)撤蟆,對(duì)不用的局部變量奕塑,要記得手動(dòng)刪除

閉包中使用this

上面我已經(jīng)說(shuō)過(guò),this與arguments的特殊之處家肯,即每個(gè)函數(shù)都會(huì)有自己的this和arguments龄砰,所以不可能直接訪問(wèn)到父作用域的this

var name="the window";
var obj={
      name:" the object",
      sayName:function(){
              var that=this;  //先將this保存到閉包可以訪問(wèn)的地方,
              return function(){
                    return that.name;
              }
      }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子换棚,更是在濱河造成了極大的恐慌式镐,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件固蚤,死亡現(xiàn)場(chǎng)離奇詭異娘汞,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)夕玩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)你弦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人燎孟,你說(shuō)我怎么就攤上這事鳖目。” “怎么了缤弦?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵领迈,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我碍沐,道長(zhǎng)狸捅,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任累提,我火速辦了婚禮尘喝,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘斋陪。我一直安慰自己朽褪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布无虚。 她就那樣靜靜地躺著缔赠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪友题。 梳的紋絲不亂的頭發(fā)上嗤堰,一...
    開(kāi)封第一講書(shū)人閱讀 52,268評(píng)論 1 309
  • 那天,我揣著相機(jī)與錄音度宦,去河邊找鬼踢匣。 笑死,一個(gè)胖子當(dāng)著我的面吹牛戈抄,可吹牛的內(nèi)容都是我干的离唬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼划鸽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼输莺!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤模闲,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后崭捍,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體尸折,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年殷蛇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了实夹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡粒梦,死狀恐怖亮航,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情匀们,我是刑警寧澤缴淋,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站泄朴,受9級(jí)特大地震影響重抖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜祖灰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一钟沛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧局扶,春花似錦恨统、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至畴蒲,卻和暖如春由捎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饿凛。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工狞玛, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人涧窒。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓心肪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親纠吴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子硬鞍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

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