面试题——循环中使用闭包解决 var 定义函数的问题

for (var i = 1; i <= 5; i++) {

    setTimeout(function timer() {

        console.log(i)

    }, i * 1000)

}

//输出结果:6 个数字 6

为什么会输出错误的结果而不是从1到6呢?

原理:JavaScript是单线程执行的,而setTimeOut函数是异步函数,它会先被放到单线程的事件队列中,在指定的事件间隔后,才会执行这个函数。但是for循环会继续执行下去,因为他并不是异步的,它会立即执行并在短时间内完成所有的迭代,所以在这个循环中每次都会设定一个定时器,并且在指定的时间后,进行日志的打印,而这时所有的迭代都已完成,所以会出现6个6这样的结果。

解决方法:

1.闭包

for (var i = 1; i <= 5; i++) {;

    (function(j) {

        setTimeout(function timer() {

            console.log(j)

        }, j * 1000)

    })(i)

}

原理:在传入函数时,传入的函数会记录当时的j的值,等到setTimeOut执行这个函数时,就可以使用到外面的function所记录的j

2.使用setTimeOut的第三个参数,传入函数(其实原理也是闭包)

for (var i = 1; i <= 5; i++) {

    setTimeout(

    function timer(j) {

        console.log(j)

    },

        i * 1000,

        i

    )

}

原理其实和前面的差不多,具体来说,当 setTimeout 的第一个参数是一个函数时,额外的参数会按顺序传递给这个函数。在这种情况下,将 i 作为第三个参数传递给 setTimeout,然后在回调函数中接收这个参数作为 j。由于 JavaScript 中的函数是闭包,回调函数会捕获传递给它的参数值,从而避免了由于循环结束后 i 的值变为 6 而导致的问题。

3.不用var使用let

for (let i = 1; i <= 5; i++) {

    setTimeout(function timer() {

        console.log(i)

    }, i * 1000)

}

原理:当使用 var 声明循环变量时,该变量存在于整个函数作用域而不是块级作用域。因此,每次迭代时 i 的值会被更新,并且所有的定时器回调函数实际执行时,它们引用的是同一个 i 变量,而这个变量在循环结束后的值是 6,使用 let 声明的变量具有块级作用域,每次迭代都会创建一个新的作用域,因此在每个定时器的回调函数中,i 的值会被正确捕获并保留,而不会受到循环结束后 i 变为 6 的影响。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值