摘要:首先引用文檔的一句話作為開(kāi)頭閉包是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。這個(gè)環(huán)境包含了這個(gè)閉包創(chuàng)建時(shí)所能訪問(wèn)的所有局部變量。
首先引用 MDN 文檔的一句話作為開(kāi)頭
閉包是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。閉包的概念
當(dāng)一個(gè)函數(shù)被 return 的時(shí)候,這個(gè)函數(shù)內(nèi)部的詞法作用域中的變量是可以被外界訪問(wèn)到的,外層函數(shù)執(zhí)行完畢時(shí)被銷(xiāo)毀,但由于內(nèi)部函數(shù)作為值返回出去,這些值得以保存下來(lái),存儲(chǔ)在內(nèi)存中,也就是私有性。
一個(gè)基本的例子:
// 來(lái)自 MDN function makeFunc() { var name = "DOG"; function displayName() { alert(name); } return displayName; } var myFunc = makeFunc(); myFunc();
閉包是由函數(shù)以及創(chuàng)建該函數(shù)的詞法環(huán)境組合而成。這個(gè)環(huán)境包含了這個(gè)閉包創(chuàng)建時(shí)所能訪問(wèn)的所有局部變量。執(zhí)行 makeFunc 時(shí)創(chuàng)建的 displayName 函數(shù)實(shí)例的引用,而 displayName 實(shí)例仍可訪問(wèn)其詞法作用域中的變量,即可以訪問(wèn)到 name 。由此,當(dāng) myFunc 被調(diào)用時(shí),name 仍可被訪問(wèn)。
閉包的應(yīng)用 私有屬性在 JavaScript 中,是沒(méi)有原生支持私有屬性的(據(jù)說(shuō)現(xiàn)在已經(jīng)有了提議),但是我們可以使用閉包來(lái)創(chuàng)建一個(gè)私有屬性。
// 來(lái)自 MDN var makeCounter = function() { var privateCounter = 0; function changeBy(val) { privateCounter += val; } return { increment: function() { changeBy(1); }, decrement: function() { changeBy(-1); }, value: function() { return privateCounter; } } }; var counter = makeCounter(); console.log(counter.privateCounter); // undefined console.log(counter.value()); // 0存儲(chǔ)變量
function func() { var x = 100; return { function() { return x; } } } var m = func(); //運(yùn)行函數(shù),變量 x 被 m 引用
此時(shí) m 引用了變量 x ,所以函數(shù)執(zhí)行后 x 不會(huì)被釋放,可以把比較重要或者計(jì)算耗費(fèi)很大的值存在 x 中,只需要第一次計(jì)算賦值后,就可以通過(guò) m 函數(shù)引用 x 的值,不必重復(fù)計(jì)算,同時(shí)也不容易被修改。
導(dǎo)致的問(wèn)題看一個(gè)例子:
var a = []; for(var i = 0; i < 10; i++) { a[i] = () => { return i; }; } a[6](); //10
在這個(gè)簡(jiǎn)單的函數(shù)中,變量 i 是在 for 循環(huán)中定義的,如果是在 C++ 或者 Java 中,這樣定義的變量,一旦循環(huán)結(jié)束,變量也就隨之銷(xiāo)毀,i 的作用范圍只在循環(huán)這個(gè)小塊,就稱為塊級(jí)作用域。在 JavaScript中,沒(méi)有這樣的塊級(jí)作用域。所以上一段代碼其實(shí)相當(dāng)于:
var a = []; var i = 0; for(; i < 10; i++) { a[i] = () => { return i; }; } a[6](); //10
這樣就很好理解了。由于匿名函數(shù)里面沒(méi)有 i 這個(gè)變量,在函數(shù)執(zhí)行的時(shí)候,這個(gè) i 他要從父級(jí)函數(shù)中尋找,而父級(jí)函數(shù)中的 i 在for 循環(huán)中,當(dāng)找到這個(gè) i 的時(shí)候,是 for 循環(huán)已經(jīng)循環(huán)完畢,所以所得與預(yù)想不一致。
改進(jìn):
var a = []; for(var i = 0; i < 10; i++) { a[i] = (() => { return i; })(); } a[6]; // 6總結(jié)
看到了一段很有用的話:
當(dāng)一個(gè)子函數(shù)被創(chuàng)建時(shí),是父函數(shù)的執(zhí)行導(dǎo)致的,所以當(dāng)子函數(shù)創(chuàng)建時(shí),父函數(shù)已經(jīng)處于執(zhí)行階段,所以父函數(shù)的執(zhí)行上下文已經(jīng)創(chuàng)建了。同時(shí),因?yàn)樽雍瘮?shù)也在父函數(shù)的局部變量作用域內(nèi),所以,子函數(shù)在創(chuàng)建的時(shí)候,除了要引用全局上下文,也需要引用父函數(shù)的執(zhí)行上下文。當(dāng)一個(gè)子函數(shù)執(zhí)行時(shí),因?yàn)樗瑯邮呛瘮?shù),所以它同樣需要?jiǎng)?chuàng)建自己的執(zhí)行上下文,當(dāng)它返回的時(shí)候,同樣也只解除屬性中對(duì)自身執(zhí)行上下文的引用,對(duì)父函數(shù)的執(zhí)行上下文的引用并沒(méi)有解除,這意味著,父函數(shù)的執(zhí)行上下文與子函數(shù)本身共存亡了。只要子函數(shù)還存在引用,垃圾收集器就不會(huì)銷(xiāo)毀它們所在的執(zhí)行上下文。另外,因?yàn)楦负瘮?shù)的局部變量并不在全局上下文中,所以它只能在子函數(shù)的變量解析中被訪問(wèn),自然而然就相當(dāng)于它們是子函數(shù)私有的了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/99739.html
摘要:大名鼎鼎的閉包面試必問(wèn)。閉包的作用是什么??吹介]包在哪了嗎閉包到底是什么五年前,我也被這個(gè)問(wèn)題困擾,于是去搜了并總結(jié)下來(lái)。關(guān)于閉包的謠言閉包會(huì)造成內(nèi)存泄露錯(cuò)。閉包里面的變量明明就是我們需要的變量,憑什么說(shuō)是內(nèi)存泄露這個(gè)謠言是如何來(lái)的因?yàn)椤? 本文為饑人谷講師方方原創(chuàng)文章,首發(fā)于 前端學(xué)習(xí)指南。 大名鼎鼎的閉包!面試必問(wèn)。請(qǐng)用自己的話簡(jiǎn)述 什么是「閉包」。 「閉包」的作用是什么。 首先...
摘要:完美的閉包,對(duì),閉包就這么簡(jiǎn)單。這僅僅是閉包的一部分,閉包利用函數(shù)作用域達(dá)到了訪問(wèn)外層變量的目的。此時(shí)一個(gè)完整的閉包實(shí)現(xiàn)了,的垃圾回收機(jī)制由于閉包的存在無(wú)法銷(xiāo)毀變量。 1.閉包是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)。 上面這段話來(lái)自 javascript 高級(jí)程序設(shè)計(jì) 第三版 P178 。作者說(shuō)閉包是一個(gè)函數(shù),它有訪問(wèn)另一個(gè)函數(shù)作用域中的變量的能力。 2.函數(shù)訪問(wèn)它被創(chuàng)建時(shí)所處的...
摘要:第二梯隊(duì)理解有了第一梯隊(duì)的認(rèn)識(shí),我們慢慢修正大腦中對(duì)閉包的認(rèn)識(shí)。理解這句話就可以很好的與閉包這兩個(gè)字關(guān)聯(lián)起來(lái)理解閉包這個(gè)概念了。總結(jié)第二梯隊(duì)理解閉包是一個(gè)有特定功能的函數(shù)。第四梯隊(duì)理解閉包通過(guò)訪問(wèn)外部變量,一個(gè)閉包可以維持這些變量。 閉包 閉包的概念困惑了我很久,記得當(dāng)時(shí)我面試的時(shí)候最后一面有一個(gè)問(wèn)題就是問(wèn)題關(guān)于閉包的問(wèn)題,然而到現(xiàn)在已經(jīng)完全不記得當(dāng)時(shí)的題目是啥了,但仍然能夠回憶起當(dāng)時(shí)...
摘要:到底什么是閉包這個(gè)問(wèn)題在面試是時(shí)候經(jīng)常都會(huì)被問(wèn),很多小白一聽(tīng)就懵逼了,不知道如何回答好。上面這么說(shuō)閉包是一種特殊的對(duì)象。閉包的注意事項(xiàng)通常,函數(shù)的作用域及其所有變量都會(huì)在函數(shù)執(zhí)行結(jié)束后被銷(xiāo)毀。從而使用閉包模塊化代碼,減少全局變量的污染。 閉包,有人說(shuō)它是一種設(shè)計(jì)理念,有人說(shuō)所有的函數(shù)都是閉包。到底什么是閉包?這個(gè)問(wèn)題在面試是時(shí)候經(jīng)常都會(huì)被問(wèn),很多小白一聽(tīng)就懵逼了,不知道如何回答好。這個(gè)...
摘要:但是閉包也不是什么復(fù)雜到不可理解的東西,簡(jiǎn)而言之,閉包就是閉包就是函數(shù)的局部變量集合,只是這些局部變量在函數(shù)返回后會(huì)繼續(xù)存在??上У氖?,并沒(méi)有提供相關(guān)的成員和方法來(lái)訪問(wèn)閉包中的局部變量。 (收藏自 技術(shù)狂) 前言:還是一篇入門(mén)文章。Javascript中有幾個(gè)非常重要的語(yǔ)言特性——對(duì)象、原型繼承、閉包。其中閉包 對(duì)于那些使用傳統(tǒng)靜態(tài)語(yǔ)言C/C++的程序員來(lái)說(shuō)是一個(gè)新的語(yǔ)言特性。本文將...
摘要:也許最好的理解是閉包總是在進(jìn)入某個(gè)函數(shù)的時(shí)候被創(chuàng)建,而局部變量是被加入到這個(gè)閉包中。在函數(shù)內(nèi)部的函數(shù)的內(nèi)部聲明函數(shù)是可以的可以獲得不止一個(gè)層級(jí)的閉包。 前言 總括 :這篇文章使用有效的javascript代碼向程序員們解釋了閉包,大牛和功能型程序員請(qǐng)自行忽略。 譯者 :文章寫(xiě)在2006年,可直到翻譯的21小時(shí)之前作者還在完善這篇文章,在Stackoverflow的How do Java...
閱讀 2014·2021-09-22 16:05
閱讀 9336·2021-09-22 15:03
閱讀 2894·2019-08-30 15:53
閱讀 1707·2019-08-29 11:15
閱讀 917·2019-08-26 13:52
閱讀 2361·2019-08-26 11:32
閱讀 1811·2019-08-26 10:38
閱讀 2576·2019-08-23 17:19