可以訪問另外一個函數做用域的變量的函數。清晰的講:閉包就是一個函數,這個函數可以訪問其餘函數的做用域中的變量。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 for (var 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 for (var 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
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 }
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
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隨着閉包函數的退出,執行環境銷燬,變量回收