閉包

前情提要:

?JS變量分為兩種:局部變量全局變量

*函數(shù)內(nèi)部可以直接訪問(wèn)全局變量。

函數(shù)內(nèi)部直接訪問(wèn)全局變量

*而函數(shù)外部卻無(wú)法訪問(wèn)函數(shù)內(nèi)部的變量。

函數(shù)外部無(wú)法訪問(wèn)局部變量

引申出一個(gè)問(wèn)題:如何在函數(shù)外部訪問(wèn)函數(shù)內(nèi)部的變量呢?

函數(shù)外部訪問(wèn)局部變量

? ?既然inner可以讀取outer中的局部變量,那么只要把inner作為返回值,我們就可以在outer外部讀取它的內(nèi)部變量了嗎 。

? ? 于是“閉包”概念誕生。

什么是閉包?

? ? ?閉包就是:能夠讀取其他函數(shù)內(nèi)部變量的【函數(shù)】,在javascript中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,所以閉包可以理解成“定義在一個(gè)函數(shù)內(nèi)部的【函數(shù)】“。在本質(zhì)上,閉包是將函數(shù)內(nèi)部和函數(shù)外部連接起來(lái)的橋梁。

? ? ?進(jìn)一步說(shuō):一個(gè)函數(shù)和對(duì)其周圍狀態(tài)(lexical environment,詞法環(huán)境)的引用捆綁在一起(或者說(shuō)函數(shù)被引用包圍),這樣的組合就是閉包closure)。也就是說(shuō),閉包讓你可以在一個(gè)內(nèi)層函數(shù)中訪問(wèn)到其外層函數(shù)的作用域。在 JavaScript 中,每當(dāng)創(chuàng)建一個(gè)函數(shù),閉包就會(huì)在函數(shù)創(chuàng)建的同時(shí)被創(chuàng)建出來(lái)。

閉包特點(diǎn):1:引用外部函數(shù)變量對(duì)象中的值;2:在外部函數(shù)的外部被調(diào)用

簡(jiǎn)單的閉包實(shí)現(xiàn)
外部函數(shù)訪問(wèn)局部變量


閉包的作用

? ? 閉包可以用來(lái)【間接的訪問(wèn)一個(gè)變量】,相當(dāng)于把【變量隱藏】,如果寫全局變量就可能會(huì)被人隨意修改,所以我們可以定義一個(gè)不能讓人【直接訪問(wèn)】到的局部變量,然后再寫一個(gè)【函數(shù)】作為訪問(wèn)器把變量暴露出去。

從堆棧的角度看閉包

? ? ??在程序運(yùn)行時(shí),計(jì)算機(jī)會(huì)為應(yīng)用程序分配一定的內(nèi)存空間;應(yīng)用程序則會(huì)自行分配所獲得的內(nèi)存空間,其中一部分被用于記錄程序中正在調(diào)用的各個(gè)函數(shù)的運(yùn)行情況,這就是函數(shù)的調(diào)用棧。常規(guī)的函數(shù)調(diào)用總是會(huì)在調(diào)用棧最上層添加一個(gè)新的堆棧幀(stack frame,也翻譯為“棧幀”或簡(jiǎn)稱為“幀”),這個(gè)過(guò)程被稱作“入?!被颉皦簵!保ㄒ饧窗研碌膸瑝涸跅m敚?。

? ?回顧基礎(chǔ):基本變量的值一般都是存在棧內(nèi)存中,而對(duì)象類型的變量的值存儲(chǔ)在堆內(nèi)存中,棧內(nèi)存存儲(chǔ)對(duì)應(yīng)空間地址。

創(chuàng)建棧流程

? ? ? 首先在全局執(zhí)行環(huán)境中,我們可以訪問(wèn)到變量a和fn,進(jìn)入fn時(shí)棧內(nèi)存會(huì)push一個(gè)fn的執(zhí)行環(huán)境,這個(gè)環(huán)境里有變量b和函數(shù)fn1,也可以訪問(wèn)到全局的執(zhí)行環(huán)境。進(jìn)入fn1時(shí),棧內(nèi)存會(huì)push一個(gè)fn1的執(zhí)行環(huán)境,這個(gè)執(zhí)行環(huán)境下無(wú)變量,但是可以訪問(wèn)到fn執(zhí)行環(huán)境和全局環(huán)境下的變量。

? ? ?隨著fn1()執(zhí)行完畢,fn1的執(zhí)行環(huán)境被杯銷毀,接著執(zhí)行完fn(),fn的執(zhí)行環(huán)境也會(huì)被銷毀,只剩全局的執(zhí)行環(huán)境下,現(xiàn)在沒(méi)有b變量,和fn1函數(shù)對(duì)象了,只有a 和 fn(函數(shù)聲明作用域是window下)。

? ? 在函數(shù)內(nèi)訪問(wèn)某個(gè)變量是根據(jù)函數(shù)作用域鏈來(lái)判斷變量是否存在的,而函數(shù)作用域鏈?zhǔn)浅绦蚋鶕?jù)函數(shù)所在的執(zhí)行環(huán)境棧來(lái)初始化的,因?yàn)槌绦蛟谠L問(wèn)變量時(shí),是【向底層棧一個(gè)個(gè)找】的。

閉包實(shí)際情況:

當(dāng)執(zhí)行完result = outer這一句之后,outer函數(shù)并沒(méi)有被銷毀,因?yàn)樗锩娴淖兞咳员籭nner的函數(shù)作用域鏈所引用,當(dāng)執(zhí)行完inner之后,inner和outer的執(zhí)行環(huán)境才會(huì)被銷毀。

閉包的優(yōu)缺點(diǎn)

它的最大用處有兩個(gè):

? ? ? ? ?1、可以讀取函數(shù)內(nèi)部的變量

? ? ? ? ?2、就是讓這些變量的值始終保持在內(nèi)存中。

閉包的缺點(diǎn)就是常駐內(nèi)存會(huì)【增大內(nèi)存使用量】,并且使用不當(dāng)很容易造成內(nèi)存泄露?!禞avaScript高級(jí)編程》書(shū)中建議:由于閉包會(huì)攜帶包含它的函數(shù)的作用域,因?yàn)闀?huì)比其他函數(shù)占用更多內(nèi)容,過(guò)度使用閉包,會(huì)導(dǎo)致內(nèi)存占用過(guò)多。

如果不是因?yàn)槟承┨厥馊蝿?wù)而需要閉包,在沒(méi)有必要的情況下,在其它函數(shù)中創(chuàng)建函數(shù)是不明智的,因?yàn)殚]包對(duì)腳本性能具有負(fù)面影響,包括處理速度和內(nèi)存消耗。

閉包的使用場(chǎng)景

1:setTimeout/setInterval

2:回調(diào)函數(shù)(callback)

3:事件句柄(event handle)



參考博客:

1:https://zhuanlan.zhihu.com/p/22486908

2:https://www.cnblogs.com/sandaizi/p/11582488.html

3:http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、什么是閉包? 閉包是指有權(quán)訪問(wèn)另外一個(gè)函數(shù)作用域中的變量的函數(shù)??梢岳斫鉃?能夠讀取另一個(gè)函數(shù)作用域的變量的函...
    為光pig閱讀 879評(píng)論 0 0
  • 閉包是js開(kāi)發(fā)慣用的技巧,什么是閉包? 閉包就是 能夠訪問(wèn)另一個(gè)函數(shù)作用域的變量的函數(shù) function f1...
    Nicholas_liang閱讀 452評(píng)論 0 2
  • 閉包是js開(kāi)發(fā)慣用的技巧,什么是閉包?閉包指的是:能夠訪問(wèn)另一個(gè)函數(shù)作用域的變量的函數(shù)。清晰的講:閉包就是一個(gè)函數(shù)...
    下一站深圳閱讀 116,703評(píng)論 35 91
  • 前言 面試問(wèn)題: 說(shuō)一下對(duì)變量提升的理解 說(shuō)明this的幾種不同的使用場(chǎng)景 創(chuàng)建10個(gè) 標(biāo)簽,點(diǎn)擊的時(shí)候彈出來(lái)對(duì)應(yīng)...
    陳觀齊閱讀 325評(píng)論 0 1
  • 1.什么是閉包? 要了解什么是閉包,首先你要了解作用域。 js的作用域分兩種,全局作用域和局部作用域。 我們知道在...
    zhudying閱讀 443評(píng)論 0 1

友情鏈接更多精彩內(nèi)容