带有 Javascript 回调的闭包

Closures with Javascript callbacks

本文关键字:闭包 回调 Javascript 带有      更新时间:2023-09-26

我以为我很好地理解了Javascript的闭包,但显然我不是。 以下代码不起作用。 如何让它在 1 秒延迟后在控制台中打印出从 0 到 9 的所有数字? 目前,它只打印"未定义"十次。

注意:我不是在寻找更简单的锻炼来延迟后打印数字。 这个问题是关于理解闭包的。

<script>
for(var i=0;i<10;i++){
    setTimeout(function(i){console.log(i)}, 1000)
}
</script>

闭包在 JavaScript 中很重要,但重要的是要了解你到底在closing什么。返工您当前的代码(有点(。

function(){
    var i;
    for(i=0;i<10;i++){
        setTimeout(function(){
            console.log(i);
        }, 1000);
    }
}

在此示例中,您的代码基本上是在 var i; 上关闭的,这意味着当计时器运行时,它将读取 var i; 的值并将其打印出来。在这种情况下,如您所见,当计时器运行时,循环已完成,值为 10 .

您要做的是创建一个新的函数作用域,用于捕获特定时间的i值。

function(){
    var i;
    for(i=0;i<10;i++){
        (function(iInner){
            setTimeout(function(){
                console.log(iInner);
            }, 1000);
        })(i);
    }
}

此示例将创建一个新的匿名函数,然后立即在循环中调用它,并将 i 的当前值传递给它,以便当您的计时器读取 iInner 时,它将读取传递到函数中的值,而不是来自 var i; 的值。如果你愿意,你也可以打电话给iInner i,但为了清楚起见,我使用了两个不同的名字。

您还可以使用一些帮助程序,例如.bind,它基本上会自动为您创建一个新的匿名函数,并传入这样的参数。

function(){
    var i;
    for(i=0;i<10;i++){
        setTimeout(function(iInner){
            console.log(iInner);
        }.bind(null, i), 1000);
    }
}

<func>.bind 将获取 i 的值并返回一个新函数,该函数在调用时将这些参数传递给 <func>,并且您不必创建另一层嵌套。

这就是你的做法。创建一个 IIFE(立即调用的函数表达式(,该表达式返回打印到控制台的函数。记住 i 的值,应该被内部函数吞噬,通过将其作为参数传递。

setTimeout 期望一个"函数"作为第一个参数,这就是我们从 IIFE 返回函数的原因。

for(var i=0;i<10;i++){
    setTimeout((function(i) {
        return function() {
            console.log(i);
        }
    })(i), 1000)
}

谢谢

您已经定义了回调函数来获取参数 i ,该参数屏蔽了在 for 循环中声明的可关闭i。因此,请将其更改为:

<script>
for(var i=0;i<10;i++){
    setTimeout(function(){console.log(i)}, 1000)
}
</script>

编辑:对不起,我没有看你问题的总体意图。就闭包的工作方式而言,函数对象捕获对封闭作用域中任何变量的引用,该变量从函数体内部引用,并且不绑定到主体内的任何局部变量(参数或显式var声明(。这就是为什么你最初的尝试没有奏效;i绑定到本地参数。

函数

对象捕获闭包变量在定义函数时拥有的值;它捕获对它的引用。因此,您不能迭代单个变量(我说的是 for 循环中声明的var i(,目的是为每个后续函数定义关闭该值。值未关闭;变量是。

但是,您可以通过关闭具有定义函数时要捕获的值的临时局部区域来有效地关闭值。它需要创建一个新的函数作用域并在该作用域内定义闭合函数,围绕具有所需值的局部(函数参数(闭合:

<script>
for (var i_outer = 0; i_outer < 10; ++i_outer)
    setTimeout((function(i_inner) { return function() { console.log(i_inner); }; })(i_outer), 1000 );
</script>