JS閉包

閉包

  可以訪問另外一個函數做用域的變量的函數。清晰的講:閉包就是一個函數,這個函數可以訪問其餘函數的做用域中的變量。es6

下面inner 就是一個閉包函數,由於他可以訪問到outer函數的做用域windows

1 function outer() { 2      var  a = '變量1'
3      var  inner = function () { 4  console.info(a) 5  } 6     return inner; 7 }

  閉包是站在做用域的角度上來定義的,由於inner訪問到outer做用域的變量,因此inner就是一個閉包函數。雖然定義很簡單,可是有不少坑點,好比this指向、變量的做用域,稍微不注意可能就形成內存泄露。數組

坑點一,引用的變量可能發生變化

1 function outer() { 2       var result = []; 3       forvar i = 0; i<10; i++){ 4         result.[i] = function () { 5  console.info(i) 6  } 7  } 8      return result 9 }

  看樣子result每一個閉包函數對打印對應數字,1,2,3,4,...,10, 實際不是,由於每一個閉包函數訪問變量i是outer執行環境下的變量i,隨着循環的結束,i已經變成10了,因此執行每一個閉包函數,結果打印10, 10, ..., 10。這時,可使用閉包保存臨時數據:閉包

 1 function outer() {  2       var result = [];  3       forvar i = 0; i<10; i++){  4         result.[i] = function (num) {  5              return function() {  6  console.info(num);  7  }  8  }(i)  9  } 10      return result 11 }

此時訪問的num,是上層函數執行環境的num,數組有10個函數對象,每一個對象的執行環境下的number都不同。app

坑點二,this指向問題

1 var object = { 2      name: ''object"3  getName: function() { 4  return function() { 5  console.info(this.name) 6  } 7  } 8 } 9 object.getName()()    // underfined

由於裏面的閉包函數是在window做用域下執行的,也就是說,this指向windows函數

坑點三,內存泄露問題

1 function showId() { 2     var el = document.getElementById("app") 3     el.onclick = function(){ 4  aler(el.id) 5  } 6 }

這樣會致使閉包引用外層的el,當執行完showId後,el沒法釋放,所以須要手動置空this

1 function showId() { 2     var el = document.getElementById("app") 3     var id  = el.id 4     el.onclick = function(){ 5  aler(id) 6  } 7     el = null  // 主動釋放el
8 }

技巧1,用閉包解決遞歸調用問題

function factorial(num) { if(num<= 1) { return 1; } else { return num * factorial(num-1) } } var anotherFactorial = factorial factorial = null anotherFactorial(4)

報錯 ,由於最好是return num* arguments.callee(num-1),arguments.callee指向當前執行函數,可是在嚴格模式下不能使用該屬性也會報錯,因此藉助閉包來實現。spa

1 function newFactorial = (function f(num){ 2     if(num<1) {return 1} 3     else { 4        return num* f(num-1) 5  } 6 })

這樣就沒有問題了,實際上起做用的是閉包函數f,而不是外面的函數newFactorial。code

技巧2,用閉包模仿塊級做用域

es6沒出來以前,用var定義變量存在變量提高問題,固然如今大多用es6的let 和const 定義。對象

 1 for(var i=0; i<10; i++){  2  console.info(i)  3 }  4 alert(i)  // 變量提高,彈出10
 5 
 6 //爲了不i的提高能夠這樣作
 7 (function () {  8     for(var i=0; i<10; i++){  9  console.info(i) 10  } 11 })() 12 alert(i)  // underfined 由於i隨着閉包函數的退出,執行環境銷燬,變量回收
相關文章
相關標籤/搜索