摘要:閉包占用大量內(nèi)存通常,函數(shù)的作用域及其所有的變量都會(huì)在函數(shù)執(zhí)行結(jié)束后被銷毀。也就是說,可以通過閉包創(chuàng)建私有作用域?qū)⒛承┳兞孔鳛榫植孔兞?,避免使用全局變量而占用過多的內(nèi)存。
JavaScript——閉包理解 1、閉包是什么,如何使用?
閉包指的是函數(shù)對象可以通過作用域鏈相互關(guān)聯(lián)起來,函數(shù)體內(nèi)部的變量都可以保存在函數(shù)作用域內(nèi),也就是說閉包有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)。
下面是一個(gè)簡單閉包的函數(shù)
function mackFn() { var name = "Husky" function sayName () { console.log("name:" + name) } return sayName } var myFn = mackFn() myFn()
mackFn()創(chuàng)建了一個(gè)局部變量name和一個(gè)名為sayName()的函數(shù)。sayName()是定義在mackFn()里的內(nèi)部函數(shù),sayName()可以訪問到外部函數(shù)的變量,所以sayName()可以使用父函數(shù)mackFn()函數(shù)中聲明的變量name。myFn是執(zhí)行了mackFn時(shí)創(chuàng)建的sayName函數(shù)實(shí)例的引用,且mackFn()函數(shù)形成閉包,所以sayName實(shí)例仍可訪問其詞法作用域的變量,即可以訪問name。
2、閉包的作用有哪些?閉包其實(shí)用處很大,通過上面的例子,可以了解到閉包允許將數(shù)據(jù)與其所操作的某些數(shù)據(jù)關(guān)聯(lián)起來,因此但我們使用只有一個(gè)方法的對象的地方,就可以使用閉包。閉包可以用來訪問私有變量和模擬私有方法
通過閉包可以訪問私有變量的共有方法
閉包技術(shù)可以用來共享私有變量,下面的例子創(chuàng)建了一個(gè)addPrivateProperty()函數(shù)來實(shí)現(xiàn)私有屬性存取器方法。這個(gè)函數(shù)給對象o增加了屬性存取器方法,方法名稱為"get" + name和"set" + name。如果提供了一個(gè)判定函數(shù), setter方法就會(huì)用它來檢測參數(shù)的合法性,然后再存儲(chǔ)它, 如果判定函數(shù)返回false,setter方法拋出異常。對于兩個(gè)存取器方法來說value這個(gè)變量是私有的,沒有辦法繞過存取器方法來設(shè)置或修改這個(gè)值。
function addPrivateProperty(o, name, predicate){ var value // 私有變量 // 私有函數(shù) o["get" + name] = function() { return value } o["set" + name] = function(v) { if (predicate && !predicate(v)){ throw Error("set" + name + ": invalid value" + v) } else { value = v } } } var o = {} //設(shè)置一個(gè)空對象 addPrivateProperty(o, "Name",function(x){ return typeof x == "string" }) o.setName("Frank") //設(shè)置屬性值 console.log(o.getName()) // => "Frank"
上述的例子中,在同一個(gè)作用域鏈中定義了兩個(gè)閉包,這兩個(gè)閉包共同享用同樣的私有變量或變量。
3、閉包存在的問題閉包中的循環(huán)陷阱
通過循環(huán)創(chuàng)建多個(gè)閉包會(huì)產(chǎn)生一定的缺陷,即閉包只能取得包含函數(shù)中任何變量的最后一個(gè)值, 下面的第一個(gè)例子中,定時(shí)器函數(shù)返回的是10, 因?yàn)槊總€(gè)函數(shù)的作用域都保存著createFn()函數(shù)的活動(dòng)對象。所以它們引用的都是同一個(gè)變量n。當(dāng)createFn()函數(shù)中,執(zhí)行完循環(huán)之后變量n的值是10,此時(shí)每個(gè)定時(shí)器函數(shù)都應(yīng)用這保存變量n的同一個(gè)變量對象,所以在每個(gè)函數(shù)內(nèi)部n的值都是10
function createFn() { for (var n = 0; n < 5; n++) { setTimeout(function() { return console.log(n); }, 100 * n); } } createFn() // => 5 5 5 5 5
可以通過定義了一個(gè)匿名函數(shù)并將立即執(zhí)行該匿名函數(shù),在調(diào)用每個(gè)匿名函數(shù)的時(shí)候,傳入了變量num,由于函數(shù)參數(shù)是按值傳遞的,所以就會(huì)將變量k的當(dāng)前值賦值給匿名函數(shù)的參數(shù)num,而在這個(gè)匿名函數(shù)的內(nèi)部,又會(huì)創(chuàng)建并返回了一個(gè)訪問k的閉包,因此定時(shí)器函數(shù)中都有自己k變量的一個(gè)副本,便可以返回不同的數(shù)值。
function createFn() { for (var k = 0; k < 10; k++) { (function(num) { setTimeout(function() { return console.log(num); }, 100 * k); })(k); } } createFn(); // => 1 2 3 4 5
閉包占用大量內(nèi)存
通常,函數(shù)的作用域及其所有的變量都會(huì)在函數(shù)執(zhí)行結(jié)束后被銷毀。但是,當(dāng)函數(shù)一旦返回了閉包,這個(gè)函數(shù)的作用域?qū)?huì)一直在內(nèi)存中保存到閉包不存在為止。
但是可以通過模仿塊級(jí)作用域來實(shí)現(xiàn)。通過創(chuàng)建并立即調(diào)用一個(gè)函數(shù),函數(shù)內(nèi)部的所有變量都會(huì)被立即銷毀(除某些變量賦值給了包含作用域中的變量),這樣既可以執(zhí)行其中的代碼,又不會(huì)在內(nèi)存中留在對該函數(shù)的引用。
function Fn(count) { (function() { for(var i = 0; i < count; i++) { console.log(i) } })() console.log("i:" + i) // 拋出錯(cuò)誤 } Fn(5)
通過創(chuàng)建函數(shù)Fn(),在for循環(huán)外部插入一個(gè)塊級(jí)作用域(私有作用域),在匿名函數(shù)中定義的任何變量,都會(huì)在執(zhí)行結(jié)束的時(shí)候被銷毀。因此,變量i只能坐在循環(huán)中使用,使用后就被銷毀。而在使用作用域中能夠訪問count變量,是因?yàn)檫@個(gè)匿名函數(shù)是一個(gè)閉包,它能夠訪問包含作用域中的所有變量。
4、性能優(yōu)化之內(nèi)存管理通過創(chuàng)建私有作用域,在全局作用域中被函數(shù)外部使用,從而限制向全局作用域中添加過多的變量和函數(shù)。通過此方法不僅可以使用自己變量,而且不用擔(dān)心搞亂全局作用域。也就是說,可以通過閉包創(chuàng)建私有作用域?qū)⒛承┳兞孔鳛榫植孔兞?,避免使用全局變量而占用過多的內(nèi)存。
總結(jié)閉包有著其優(yōu)點(diǎn),可以利用其優(yōu)點(diǎn)實(shí)現(xiàn)很多功能,如閉包可以用來訪問私有變量和模擬私有方法(訪問私有屬性的模式有很多,以后總結(jié))等等,但是因?yàn)閯?chuàng)建閉包必須維護(hù)額外的作用域,所以過渡使用閉包會(huì)占用大量的內(nèi)存。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/107571.html
摘要:如何在初學(xué)就理解閉包你需要接著讀下去。這樣定義閉包是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。小結(jié)閉包在中隨處可見。閉包是中的精華部分,理解它需要具備一定的作用域執(zhí)行棧的知識(shí)。 這是本系列的第 4 篇文章。 作為 JS 初學(xué)者,第一次接觸閉包的概念是因?yàn)閷懗隽祟愃葡旅娴拇a: for (var i = 0; i < helpText.length; i++) { var item = he...
摘要:但是閉包也不是什么復(fù)雜到不可理解的東西,簡而言之,閉包就是閉包就是函數(shù)的局部變量集合,只是這些局部變量在函數(shù)返回后會(huì)繼續(xù)存在??上У氖?,并沒有提供相關(guān)的成員和方法來訪問閉包中的局部變量。 (收藏自 技術(shù)狂) 前言:還是一篇入門文章。Javascript中有幾個(gè)非常重要的語言特性——對象、原型繼承、閉包。其中閉包 對于那些使用傳統(tǒng)靜態(tài)語言C/C++的程序員來說是一個(gè)新的語言特性。本文將...
摘要:也許最好的理解是閉包總是在進(jìn)入某個(gè)函數(shù)的時(shí)候被創(chuàng)建,而局部變量是被加入到這個(gè)閉包中。在函數(shù)內(nèi)部的函數(shù)的內(nèi)部聲明函數(shù)是可以的可以獲得不止一個(gè)層級(jí)的閉包。 前言 總括 :這篇文章使用有效的javascript代碼向程序員們解釋了閉包,大牛和功能型程序員請自行忽略。 譯者 :文章寫在2006年,可直到翻譯的21小時(shí)之前作者還在完善這篇文章,在Stackoverflow的How do Java...
摘要:當(dāng)面試中讓我解釋一下閉包時(shí)我懵逼了。這個(gè)解釋開始可能有點(diǎn)晦澀,讓我們抽絲剝繭摘下閉包的真面目。此文不詳述作用域有專門的主題闡述,不過作用域是理解閉包原理的基礎(chǔ)。這才是閉包的真正便利之處。閉包使用不當(dāng)就會(huì)很坑。 原文鏈接 為什么深度學(xué)習(xí)JavaScript? JavaScript如今是最流行的編程語言之一。它運(yùn)行在瀏覽器、服務(wù)器、移動(dòng)設(shè)備、桌面應(yīng)用,也可能包括冰箱。無需我舉其他再多不相干...
摘要:譯者按在上一篇博客,我們通過實(shí)現(xiàn)一個(gè)計(jì)數(shù)器,了解了如何使用閉包,這篇博客將提供一些代碼示例,幫助大家理解閉包。然而,如果通過代碼示例去理解閉包,則簡單很多。不過,將閉包簡單地看做局部變量,理解起來會(huì)更加簡單。 - 譯者按: 在上一篇博客,我們通過實(shí)現(xiàn)一個(gè)計(jì)數(shù)器,了解了如何使用閉包(Closure),這篇博客將提供一些代碼示例,幫助大家理解閉包。 原文: JavaScript Clos...
摘要:閉包引起的內(nèi)存泄漏總結(jié)從理論的角度將由于作用域鏈的特性中所有函數(shù)都是閉包但是從應(yīng)用的角度來說只有當(dāng)函數(shù)以返回值返回或者當(dāng)函數(shù)以參數(shù)形式使用或者當(dāng)函數(shù)中自由變量在函數(shù)外被引用時(shí)才能成為明確意義上的閉包。 文章同步到github js的閉包概念幾乎是任何面試官都會(huì)問的問題,最近把閉包這塊的概念梳理了一下,記錄成以下文章。 什么是閉包 我先列出一些官方及經(jīng)典書籍等書中給出的概念,這些概念雖然...
閱讀 1307·2021-11-16 11:44
閱讀 3774·2021-10-09 10:01
閱讀 1769·2021-09-24 10:31
閱讀 3858·2021-09-04 16:41
閱讀 2528·2021-08-09 13:45
閱讀 1226·2019-08-30 14:08
閱讀 1791·2019-08-29 18:32
閱讀 1652·2019-08-26 12:12