在開始說閉包以前,咱們要先理解一下變量的做用域,變量的做用域無非有兩種:全局做用域和局部做用域。閉包
出於種種緣由,有時候咱們須要獲得函數內部的局部變量。函數
可是,在正常狀況下這個是辦不到的,只有經過變通的方法才能實現。性能
這個方法就是,在函數的內部再定義一個函數。code
function f1() { let a = 1 function f2() { console.log(a); } }
在上面的代碼中,函數 f2 就被定義在了 函數 f1 中,這時 f1 內的全部局部變量對 f2 都是可見的。對象
可是反過來就不行,f2 內部的局部變量對 f1 就是不可見的。內存
那麼既然 f2 能夠讀取 f1 中的變量,那麼只要把 f2 做爲返回值,咱們不就能夠在 f1 外部讀取它內部的變量了嗎!作用域
function f1() { let a = 1 function f2() { console.log(a); } return f2; } var result = f1(); result()
定義:若是一個函數用到了外部的變量,那麼這個函數加這個變量,就叫作閉包。開發
好比,這裏就是一個閉包:產品
function f1() { let a = 1 function f2() { console.log(a); } } // 函數 f2 能夠訪問外部的變量 a,那麼函數 f2 和 外部的變量 a 就構成了閉包
閉包經常用來間接訪問一個變量,換句話說,就是隱藏一個變量。io
假如咱們在開發一個商城項目,裏面有產品數量的代碼。若是不使用閉包,那麼你能夠直接使用一個全局變量:
window.number = 200
這樣子寫存在一個問題,萬一不當心把這個值改爲了 0 該怎麼辦,因此咱們不能讓人直接訪問這個變量。
使用局部變量?使用局部變量別人又沒法進行訪問。
能夠暴露一個訪問器(函數),讓別人能夠「間接訪問「。
代碼能夠這樣子寫:
!function () { var number = 200 window.addGoods = function () { number += 1 } window.deleteGoods = function () { number -= 1 } }() window.addGoods()
這個時候,你就能夠調用 window.addGoods 來添加商品,調用 deleteGoods 來下架商品。
這其中一共有兩個閉包:
因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大,因此不能濫用閉包,不然會形成網頁性能問題。
解決方法是,在退出函數以前,將不適用的局部變量所有刪除。
閉包會在父函數外部改變父函數內部的值。
因此,若是你把父函數當作對象使用,把閉包當作他的公用方法,把內部變量當作它的私有屬性,這時必定要當心,不要隨便改變父函數內部變量的值。