可以访问另外一个函数做用域的变量的函数。清晰的讲:闭包就是一个函数,这个函数可以访问其余函数的做用域中的变量。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随着闭包函数的退出,执行环境销毁,变量回收