JavaScript——閉包理解

JavaScript——閉包理解

1、閉包是什麼,如何使用?

閉包指的是函數對象可以通過作用域鏈相互關聯起來,函數體內部的變量都可以保存在函數作用域內,也就是說閉包有權訪問另一個函數作用域中的變量的函數。下面是一個簡單閉包的函數

JavaScript——閉包理解

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這個變量是私有的,沒有辦法繞過存取器方法來設置或修改這個值。

JavaScript——閉包理解

上述的例子中,在同一個作用域鏈中定義了兩個閉包,這兩個閉包共同享用同樣的私有變量或變量。

3、閉包存在的問題

通過循環創建多個閉包會產生一定的缺陷,即閉包只能取得包含函數中任何變量的最後一個值,下面的第一個例子中,定時器函數返回的是10,因為每個函數的作用域都保存著createFn()函數的活動對象。所以它們引用的都是同一個變量n。當createFn()函數中,執行完循環之後變量n的值是10,此時每個定時器函數都應用這保存變量n的同一個變量對象,所以在每個函數內部n的值都是10

JavaScript——閉包理解

可以通過定義了一個匿名函數並將立即執行該匿名函數,在調用每個匿名函數的時候,傳入了變量num,由於函數參數是按值傳遞的,所以就會將變量k的當前值賦值給匿名函數的參數num,而在這個匿名函數的內部,又會創建並返回了一個訪問k的閉包,因此定時器函數中都有自己k變量的一個副本,便可以返回不同的數值。

JavaScript——閉包理解

通常,函數的作用域及其所有的變量都會在函數執行結束後被銷燬。但是,當函數一旦返回了閉包,這個函數的作用域將會一直在內存中保存到閉包不存在為止。但是可以通過模仿塊級作用域來實現。通過創建並立即調用一個函數,函數內部的所有變量都會被立即銷燬(除某些變量賦值給了包含作用域中的變量),這樣既可以執行其中的代碼,又不會在內存中留在對該函數的引用。

JavaScript——閉包理解

通過創建函數Fn(),在for循環外部插入一個塊級作用域(私有作用域),在匿名函數中定義的任何變量,都會在執行結束的時候被銷燬。因此,變量i只能坐在循環中使用,使用後就被銷燬。而在使用作用域中能夠訪問count變量,是因為這個匿名函數是一個閉包,它能夠訪問包含作用域中的所有變量。

4、性能優化之內存管理

通過創建私有作用域,在全局作用域中被函數外部使用,從而限制向全局作用域中添加過多的變量和函數。通過此方法不僅可以使用自己變量,而且不用擔心搞亂全局作用域。也就是說,可以通過閉包創建私有作用域將某些變量作為局部變量,避免使用全局變量而佔用過多的內存。

閉包有著其優點,可以利用其優點實現很多功能,如閉包可以用來訪問私有變量和模擬私有方法(訪問私有屬性的模式有很多,以後總結)等等,但是因為創建閉包必須維護額外的作用域,所以過渡使用閉包會佔用大量的內存。

JavaScript——閉包理解


分享到:


相關文章: