1. 程式人生 > >JavaScript之閉包(重新認識)

JavaScript之閉包(重新認識)

log 變量 for 局部變量 ava logs 所在 數組函數 使用

最近又重新學習了閉包,發現之前沒有深刻理解作用域鏈,學習作用域鏈後對閉包才可以做到真正的理解。

閉包是指有權另一個函數作用域中變量的函數。要理解閉包首先理解作用域鏈。

執行環境定義了變量或函數有權訪問的其他數據,決定了它們各自的行為。每個執行環境都有與之關聯的變量對象,保存了環境中定義的所有變量和函數。只有解析器在處理數據是我才可以訪問這個變量。當代碼在一個環境中執行時,會創建變量對象的一個作用域鏈,它保證了執行環境對有權訪問的變量和函數的有序訪問。

當某個函數被調用時,會創建一個執行環境及相應的作用域鏈。作用域的最前端,始終都是當前執行代碼所在環境的變量對象,下一個變量對象來自外部環境,以此類推,直到全局作用域中的變量對象作為作用域鏈的終點。作用域鏈中一定不會包含其內部子函數的變量對象,但子函數的作用域鏈包含函數的局部變量,因此這決定創建閉包的方法

是在一個函數內部創建另一個函數,內部函數可以引用外部函數的變量。

閉包與變量

閉包只能取得函數中任何變量的最後一個值,如下創建一個數組函數

function creatFunction(){
  var result = new Array();
  for (var i=0; i<10; i++){
  result[i] = function(){
          return i;
   };
}
  return result;
}

表面上每個函數都會返回自己的索引,實際上都返回10。這是因為每個函數都引用作用域鏈中同一個變量i,當creatFunction()函數返回後,i的值是10。解決方法

(1) 創建匿名函數封裝

function creatFunction(){
  var result = new Array();
  for (var i=0; i<10; i++){
  result[i] = function(num){
            function(){
                  return num;  
         };
   }(i)
}
return result;
}

(2)使用ES6的let

ES6 新增了let命令,用來聲明變量。它的用法類似於var,但是所聲明的變量,只在let命令所在的代碼塊內有效。

function creatFunction(){
  var result = new Array();
  for (let i=0; i<10; i++){
         result[i] = function(){
             return i;
       };
  }
return result;
}

閉包特性

(1)封閉性:外界無法訪問閉包內部的數據,如果在閉包內聲明變量,外界是無法訪問的,除非閉包主動向外界提供訪問接口;

(2)持久性:一般的函數,調用完畢之後,局部活動對象就會被銷毀,內存中僅保存全局作用域。而對於閉包來說,在外部函數被調用之後,閉包結構依然保存在。

閉包問題

(1) 占用內存。由於閉包攜帶包含它函數的作用域,因此會比其他函數占用更多內存。

(2) 引起內存泄漏。 閉包中引用HTML元素將無法被銷毀。解決方法是將需要使用的DOM元素副本的屬性保存在變量中,結束會銷毀DOM元素。

JavaScript之閉包(重新認識)