什么是闭包
在高级程序设计中对闭包定义是这样的:“闭包是指有权限访问另一个函数作用域中的变量的函数。“
闭包的使用场景:
经典例子1
function box(){
var arr = [];
for(var i=0;i<5;i++){
arr[i] = i;
}
return arr;
}
alert(box())
//正常情况不需要闭包,就可以达到预期效,输出数组结果为0,1,2,3,4
有时我们需要在for循环里面添加一个匿名函数来实现更多功能,看下面代码
function box(){
var arr = [];
for(var i=0;i<5;i++){
arr[i] = function(){
return i; //由于这个闭包的关系,他是循环完毕之后才返回,最终结果是4++是5
} //这个匿名函数里面根本没有i这个变量,所以匿名函数会从父级函数中去找i,
} //当找到这个i的时候,for循环已经循环完毕了,所以最终会返回5
return arr;
}
//alert(box()); //执行5次匿名函数本身
//alert(box()[1]); //执行第2个匿名函数本身
//alert(box().length); //最终返回的是一个数组,数组的长度为5
alert(box()[0]()); //数组中的第一个数返回的是5,这是为什么?
个人的理解是你每次在循环的时候arr[i]对应的函数是没有被调用执行的,而当我们调用box()[0]去执行内部函数时,外部的for循环已经执行完了,是5
所以最终得到的box是[5,5,5,5,5]
解决方案1
在每次循环时,让函数执行(可以用立即执行函数)
function box(){
var arr = [];
for(var i=0;i<5;i++){
arr[i] = (function(num){ //自我执行,并传参(将匿名函数形成一个表达式)(传递一个参数)
return num; //这里的num写什么都可以
})(i); //这时候这个括号里面的i和上面arr[i]的值是一样的都是取自for循环里面的i
}
return arr;
}
//alert(box());
//alert(box()[1]);
//alert(box().length);
alert(box()[0]);
经典例子2,使用闭包解决var定义函数的问题
for ( var i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
首先因为setTimeout是个异步函数,所有会先把循环全部执行完毕,这时候 i 就是 6 了,所以会输出一堆 6。
解决办法两种,第一种使用闭包
for (var i = 1; i <= 5; i++) {
(function(j) {
setTimeout(function timer() {
console.log(j);
}, j * 1000);
})(i);
}
第二种就是使用setTimeout的第三个参数
for ( var i=1; i<=5; i++) {
setTimeout( function timer(j) {
console.log( j );
}, i*1000, i);
}
第三种就是使用let定义i
for ( let i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
(对于定义let来说,它会创建一个块级作用域,来保存循环执行时每次i的值)
参考文章:https://www.cnblogs.com/ZinCode/p/5551907.html
https://www.cnblogs.com/pssp/p/5224509.html