【javascript】闭包

2023-11-14

通过定时器从第一个元素开始往后,每隔一秒输出arr数组中的一个元素。

<script>
    var arr = ['one', 'two', 'three'];
    for(var i = 0; i < arr.length; i++) {
    setTimeout(function () {
        console.log(arr[i]);
    }, i * 1000);
    }
</script>

 但是运行过后,我们却会发现结果是每隔一秒输出一个“undefined”。

这是为什么呢?

setTimeout()函数与for循环在调用时会产生两个独立执行上下文环境,当setTimeout()函数内部的函数执行时,for循环已经执行结束,而for循环结束的条件是最后一次i++执行完毕,此时i的值为3,所以实际上setTimeout()函数每次执行时,都会输出arr[3]的值。而因为arr数组最大索引值为2,所以会间隔一秒输出“undefined”。

尝试如下代码,发现就可以了。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <script>
        var arr = ['one', 'two', 'three'];
        for(var i = 0; i < arr.length; i++) {
        (function (time) {
            setTimeout(function () {
                console.log(arr[time]);
            }, time * 1000);
        })(i);
        }
     </script>
  </head>
  <body>
  </body>
  </html>

 对比两个代码的区别,有什么不同呢?

先谈谈什么是执行上下文环境

JavaScript每段代码的执行都会存在于一个执行上下文环境中,而任何一个执行上下文环境都会存在于整体的执行上下文环境中。根据栈先进后出的特点,全局环境产生的执行上下文环境会最先压入栈中,存在于栈底。当新的函数进行调用时,会产生的新的执行上下文环境,也会压入栈中。当函数调用完成后,这个上下文环境及其中的数据都会被销毁,并弹出栈,从而进入之前的执行上下文环境中。

第二个代码通过立即执行函数将索引i作为参数传入,在立即函数执行完成后,由于setTimeout()函数中有对arr变量的引用,其执行上下文环境不会被销毁,因此对应的i值都会存在内存中。所以每次执行setTimeout()函数时,i都会是数组对应的索引值0、1、2,从而间隔一秒输出“one”“two”“three”。

下面引出闭包的概念,即函数声明和函数表达式可以位于另一个函数的函数体内,在内部函数中可以访问外部函数声明的变量,当这个内部函数在包含它们的外部函数之外被调用时,就会形成闭包

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【javascript】闭包 的相关文章

随机推荐