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