說一說js中的閉包

不說官方給的定義,感受本身剛開始看也不是很理解。閉包

閉包 : 其實就是 該函數能使用函數外定義的變量。函數

 

爲何要使用閉包?spa

首先來講一下局部變量和全局變量的危害: 全局變量容易全局污染,局部變量又沒法共享,不能長久保存code

那閉包實現了一個什麼?對象

既能夠共享,長久保存,又不會全局污染,實際上是用來保護局部變量的。blog

閉包有什麼缺點?內存

佔內存,至於爲何佔內存,稍後會畫內存圖來講明。作用域

 

若是說你要寫一個閉包,就是抓住閉包的三個特色:get

  1. 定義外層函數,封裝被保護的局部變量
  2. 定義內層函數,執行對局部變量(外層函數的)的操做
  3. 外層函數返回內層函數的對象,而且外層函數被調用,結果保存在全局變量中
function outer(){
   var n = 1;
   function inner(){
       return  n++;
   }  
   return inner;
}
var getNum = outer();

 

因此說在你判斷閉包的時候通常是看如下三點:io

  1. 嵌套函數
  2. 內層函數必定操做了外層函數的局部變量
  3. 外層函數將內層函數返回到外部,被全局變量保存住

那一個閉包咱們又如何去判斷他的執行結果呢?

  1. 外層函數被調用了幾回,就有幾個受保護的局部變量副本
  2. 來自一個閉包的函數被調用幾回,受保護的局部變量就變化幾回

好比剛剛那個例子來講:

function outer(){
   var n = 1;
   function inner(){
       return  n++;
   }  
   return inner;
}
var getNum = outer();
//外層函數調用一次,有一個被保護的n
console.log(getNum());
//0
console.log(getNum());
//1
var getNum2 = outer();
//外層函數被調用兩次,有兩個互不干擾的n
console.log(getNum2());
//0

內存圖:

  建立函數的同時會建立兩個對象:  

        函數對象:函數的定義  (老闆)

        做用域鏈對象:保存了函數對象可用的變量的位置的對象(棧),默認第一項指向window(管理員)

  而調用函數時,又會建立一個新對象

        活動對象:專門保存局部變量的對象(這裏說一下函數中的局部變量指的是  參數  和  var聲明的)

        在做用域鏈對象中追加指向活動對象的引用

  調用後:僅僅釋放了活動對象,做用域鏈中活動對象的引用出棧,活動對象因無人引用而釋放

      (也就是說內存圖中,某一塊當沒有人指入它時,就會被釋放)

 

 除去釋放後的部分:

 

可見若是有閉包的存在,實際上是很佔內存的,它會造成這種循環的指入,使得沒法被釋放

相關文章
相關標籤/搜索