標籤:解決方案 str return 活動 html 關聯 索引 匿名函數 cti
最近又重新學習了閉包,發現之前沒有深刻理解範圍鏈,學習範圍鏈後對閉包才可以做到真正的理解。
閉包是指有權另一個函數範圍中變數的函數。要理解閉包首先理解範圍鏈。
執行環境定義了變數或函數有權訪問的其他資料,決定了它們各自的行為。每個執行環境都有與之關聯的變數對象,儲存了環境中定義的所有變數和函數。只有解析器在處理資料是我才可以訪問這個變數。當代碼在一個環境中執行時,會建立變數對象的一個範圍鏈,它保證了執行環境對有權訪問的變數和函數的有序訪問。
當某個函數被調用時,會建立一個執行環境及相應的範圍鏈。範圍的最前端,始終都是當前執行代碼所在環境的變數對象,下一個變數對象來自外部環境,以此類推,直到全域範圍中的變數對象作為範圍鏈的終點。範圍鏈中一定不會包含其內部子函數的變數對象,但子函數的範圍鏈包含函數的局部變數,因此這決定建立閉包的方法是在一個函數內部建立另一個函數,內建函式可以引用外部函數的變數。
閉包與變數
閉包只能取得函數中任何變數的最後一個值,如下建立一個數組函數
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之閉包(重新認識)