JavaScript:闭包
1、产生闭包的条件:
1、函数(外部函数)的返回值为一个函数(内部函数)
2、内部函数引用了外部函数中的变量
3、存在一个变量去接收外部函数的返回值(或者说:创造了一个不销毁的执行空间)
2、最简单的闭包案例:
function fn1(){
var a = 1;
function fn2(){
console.log(a);
}
return fn2;
}
var f = fn1();
这就是一个闭包;
3、闭包的原理:
函数在调用的时候,会在内存中临时开辟一个执行空间,当函数中的代码执行完之后,该执行空间被销毁,闭包的目的则是为了得到函数中的某些数据,不销毁该执行空间,让函数中的代码一直执行。
根据上面案例的代码进行解释:
函数 fn1 在调用时返回了一个新的函数 fn2,并将 fn2 的地址赋给了变量 f , 按照往常,fn1 的执行空间要被销毁,但是,由于 f 指向了 fn2 这个函数,而 fn2 又在 fn1 这个函数中,fn2的代码一直在被使用(因为 f 变量要在其他地方被使用,如果执行空间销毁,f变量就变为undefined,显然是不合理的), 所以 fn1 的执行空间一直存在,不会被销毁,直到对变量 f 进行重新赋值时(此时 fn2 就不再有变量指向它了),fn1的执行空间才会被销毁。
4、闭包的特点:
1、在函数外部可以使用该函数里面的数据
2、不会污染全局(如果在全局中声明了太多变量,可能导致重名等问题,不利于维护)
3、延长了函数作用域的生命周期(函数中的数据不会被垃圾回收机制回收)
5、一些闭包应用:
1、关于事件的闭包使用:
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<meta http-equiv='X-UA-Compatible' content='ie=edge'>
<title>Document</title>
</head>
<body>
<button>按钮0</button>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
</body>
</html>
<script>
var btns = document.querySelectorAll("button");
function fn(i){
return function ff(){
console.log(i);
}
}
for(var i =0; i<4; i++){
btns[i].onclick = fn(i);
}
</script>
2、关于自调用函数的闭包使用:
var f = (function fn(){
var a = 0;
return function ff(){
a++;
console.log(a);
}
})();