面试复习之js理解闭包

什么是闭包

在高级程序设计中对闭包定义是这样的:“闭包是指有权限访问另一个函数作用域中的变量的函数。“

闭包的使用场景:

经典例子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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值