九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
javascript執(zhí)行上下文、作用域與閉包(第六篇)

終于講到閉包了,當(dāng)你在百度上搜索閉包時(shí),你會(huì)被搜索出來(lái)的結(jié)果嚇一跳,我的天,為什么說(shuō)得都不一樣?直到把所有的解釋都看過(guò)了,我就只想說(shuō)一句,到底誰(shuí)說(shuō)的是對(duì)的…

在這么多的不同解釋里,我認(rèn)真思考了很久,到底該相信誰(shuí)?最后我選擇相信大道至簡(jiǎn),因?yàn)槲沂冀K覺(jué)得理論來(lái)源于實(shí)踐,而實(shí)踐一定不是在象牙塔里,而是可以摸得到的簡(jiǎn)單的東西。

下面就來(lái)講最原始的閉包的示例:

function fn(){var max=10;return function bar(x){if(x>max){alert(x);}}}var f1=fn();f1(15);//15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

如上代碼,bar函數(shù)作為返回值,賦值給f1變量。執(zhí)行f1(15)時(shí),就相當(dāng)于執(zhí)行bar(15),沿著作用域鏈取到fn作用域下的max變量的值。

這已經(jīng)產(chǎn)生了一個(gè)最基本的閉包,用自然語(yǔ)言描述的話就是:

(1)定義普通函數(shù) A

(2)在 A 中定義普通函數(shù) B

(3)在 A 中返回 B

(4)執(zhí)行 A, 并把 A 的返回結(jié)果賦值給變量 C

(5)執(zhí)行 C

而它的形式就是用“return”作為橋梁,鏈接A外的變量C和A內(nèi)的變量B。

用一個(gè)歸納的話說(shuō)就是:

當(dāng)一個(gè)內(nèi)部函數(shù)被其外部函數(shù)之外的變量引用時(shí),就形成了一個(gè)閉包

如果你認(rèn)為這就是閉包的全部,那你就有些狹隘了。

下面一個(gè)例子,就展示了這個(gè)狹隘之處:

function A(){    var count=0;    function B(){        count++;        alert(count);    }    return B;} var c=A(); c();//1 c();//2 c();//3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

那么你就會(huì)驚奇于閉包還有如此神秘的一面,其實(shí)對(duì)于這一面,網(wǎng)上有很多解釋?zhuān)忉尩梦寤ò碎T(mén),但大都沒(méi)解釋到本質(zhì)上。

其實(shí)這一系列的文章的標(biāo)題都是“javascript執(zhí)行上下文、作用域與閉包”,說(shuō)明閉包與執(zhí)行上下文,作用域是有緊密聯(lián)系的,下面就來(lái)演示一下閉包那神秘的一面的本質(zhì)。

咱們可以拿本文的第一段代碼(稍作修改)來(lái)分析一下。

function fn(){var max=10;return function bar(x){if(x>max){alert(x);}}}var f1=fn(),max=100;f1(15);//15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

我們來(lái)一步一步揭開(kāi)那神秘的面紗:

在這之前,告訴大家一個(gè)很重要的東西—-我們?cè)谇懊嬷v執(zhí)行上下文棧時(shí)當(dāng)一個(gè)函數(shù)被調(diào)用完成之后,其執(zhí)行上下文將被被彈出,即銷(xiāo)毀,其中的變量也會(huì)被同時(shí)銷(xiāo)毀。

但我們要銘記:在閉包里,函數(shù)調(diào)用完成之后,其執(zhí)行上下文環(huán)境不會(huì)立即被銷(xiāo)毀。(這句話是不正確的,但這里讀者可以先用這個(gè)錯(cuò)誤的解釋去看下面的步驟,先對(duì)閉包形成的原因有一個(gè)大致的了解,最終正確的理解在 厚積薄發(fā)—從此再也不用擔(dān)心閉包問(wèn)題

第一步,代碼執(zhí)行前生成全局上下文環(huán)境,并在執(zhí)行時(shí)對(duì)其中的變量進(jìn)行賦值。此時(shí)全局上下文環(huán)境是活動(dòng)狀態(tài):

第二步,執(zhí)行第17行代碼時(shí),調(diào)用fn(),產(chǎn)生fn()執(zhí)行上下文環(huán)境,壓棧,并設(shè)置為活動(dòng)狀態(tài)。

第三步,執(zhí)行完第17行,fn()調(diào)用完成。按理說(shuō)應(yīng)該銷(xiāo)毀掉fn()的執(zhí)行上下文環(huán)境,但是因?yàn)閳?zhí)行fn()時(shí),返回的是一個(gè)函數(shù)。函數(shù)的特別之處在于可以創(chuàng)建一個(gè)獨(dú)立的執(zhí)行上下文,當(dāng)代碼執(zhí)行到return時(shí),按理說(shuō)應(yīng)該把fn()的執(zhí)行上下文銷(xiāo)毀,但是由于return的bar()存在對(duì)fn()上下文的引用,(因?yàn)榇嬖趯?duì)變量max的需要)所以不能將其銷(xiāo)毀,這里就要提到j(luò)s的垃圾回收機(jī)制,當(dāng)一個(gè)函數(shù)不存在外部對(duì)它的引用的時(shí)候,就自動(dòng)將其銷(xiāo)毀。這里存在對(duì)把不能把fn()上下文銷(xiāo)毀。

第四步,執(zhí)行到第18行時(shí),全局上下文環(huán)境將變?yōu)榛顒?dòng)狀態(tài),但是fn()上下文環(huán)境依然會(huì)在執(zhí)行上下文棧中。另外,執(zhí)行完第18行,全局上下文環(huán)境中的max被賦值為100。如下圖:

第五步,執(zhí)行到第20行,執(zhí)行f1(15),即執(zhí)行bar(15),創(chuàng)建bar(15)上下文環(huán)境,并將其設(shè)置為活動(dòng)狀態(tài)

執(zhí)行bar(15)時(shí),max是自由變量,需要向創(chuàng)建bar函數(shù)的作用域中查找,找到了max的值為10,

這里的重點(diǎn)就在于,創(chuàng)建bar函數(shù)是在執(zhí)行fn()時(shí)創(chuàng)建的。fn()早就執(zhí)行結(jié)束了,但是fn()執(zhí)行上下文環(huán)境還存在與棧中,因此bar(15)時(shí),max可以查找到。如果fn()上下文環(huán)境銷(xiāo)毀了,那么max就找不到了。

可以看到,使用閉包會(huì)使變量保存在內(nèi)存中,但是缺點(diǎn)就是會(huì)增加內(nèi)存開(kāi)銷(xiāo)。

在網(wǎng)上有些資料解釋閉包的主要用途有兩個(gè),一個(gè)是可以使外部變量訪問(wèn)到一個(gè)函數(shù)的內(nèi)部變量,一個(gè)是使變量保存在內(nèi)存中。其實(shí)這句話不太貼切,正確的說(shuō)法應(yīng)該是:使外部變量訪問(wèn)到一個(gè)函數(shù)的內(nèi)部變量是閉包的形式,使變量保存在內(nèi)存中是閉包的工作原理。

到這里,如果覺(jué)得有種恍然大悟的感覺(jué),不妨試一試下面的例子

function A(){    var count=0;    function B(){        count++;        alert(count);    }    return B;} var c=A(); c();//1 c();//2 c();//3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

大家可以試一試解釋為什么三次調(diào)用c(),結(jié)果分別是1,2,3呢?

如果還有些不懂,我會(huì)在下一篇里詳細(xì)講一下我的理解。


本文參考了王福朋老師的深入理解javascript原型和閉包(15)——閉包

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
javascript語(yǔ)言精粹 筆記
前端基礎(chǔ)進(jìn)階(四):詳細(xì)圖解作用域鏈與閉包
深入理解JavaScript作用域和作用域鏈
JavaScript 之 作用域
深入理解javascript原型和閉包(18)
用一個(gè)例子理解JS函數(shù)的底層處理機(jī)制
更多類(lèi)似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服