如何将变量传递给匿名函数

时间:2012-04-18 10:31:12

标签: javascript

我想传递变量setTimeout函数并对其执行某些操作。当我提醒i的价值时,它会显示我没想到的数字。我做错了什么?我想要从1到8的日志值。

var end=8;
for (var i = 1; i < end; i ++) {
       setTimeout(function (i) {
           console.log(i);   

       }, 800);
   }

4 个答案:

答案 0 :(得分:11)

解决此问题的标准方法是使用工厂函数:

var end=8;
for (var i = 1; i < end; i ++) {
       setTimeout(makeResponder(i), 800);
   }

function makeResponder(index) {
    return function () {
        console.log(index);   
   };
}

Live example | source

在那里,我们在循环中调用 makeResponder,并返回一个函数,该函数关闭传递给它的参数(index)而不是{{1}变量。 (这很重要。如果您刚刚从匿名函数中删除了i参数,那么您的代码将部分工作,但所有函数在运行时都会看到i的值,而不是最初安排的时间;在您的示例中,他们都会看到i。)


更新从以下评论中

  

...如果我以这种方式调用它8

会是正确的吗?

是的,如果您的目标是让每次通话比最后一次通话晚大约800毫秒,那么这将有效:

Live example | source

  

我试过了setTimeout(makeResponder(i),i*800);,但它无法正常使用

您不会以这种方式使用setTimeout(makeResponder(i),setInterval(i));function setInterval(index) { console.log(index*800); return index*800; },并且可能根本不想使用它。


进一步更新:您在下面说过:

  

我需要先迭代打印8延迟8秒,第二次迭代打印7延迟7秒........打印2延迟2秒...打印0延迟0秒

您只需使用第二次超时再次应用上述原则:

setInterval

Live example | source

我认为你现在拥有了实现这一目标所需的所有工具。

答案 1 :(得分:2)

你的问题是你在i函数触发后的一段时间内引用变量setTimeout(),到那时,i的值已经改变(它已经结束了) for循环。要使每个setTimeout保持适当的i值,您必须为每个i回调单独捕获该值setTimeout()

使用工厂函数的上一个答案很好,但是我发现自执行函数比工厂函数更容易键入和跟踪,但两者都可以工作,因为它们都在闭包中捕获你想要的变量,这样你就可以参考了它们在setTimeout回调中的静态值。

以下是自执行函数如何解决此问题:

var end=8;
for (var i = 1; i < end; i ++) {
       (function (index) {
           setTimeout(function() {
               console.log(index);
           }, 800);
       })(i);
   }

要设置超时延迟与i的值成比例,您可以这样做:

var end=8;
for (var i = 1; i < end; i ++) {
    (function (index) {
        setTimeout(function() {
            console.log(index);
        }, index * 800);
    })(i);
}

自执行函数传递i的值,并且包含该值的函数内的参数名为index,因此您可以引用index来使用适当的值。

答案 2 :(得分:0)

这不起作用的主要原因是因为setTimeout设置为在800之后运行,i的范围。

执行时i的值已经改变。因此,无法收到明确的结果。就像TJ说的那样,解决这个问题的方法是通过处理函数。

function handler( var1) {
    return function() {
      console.log(var1);  
    }        
}

var end = 8;
for (var i = 1; i < end; i++) {     
   setTimeout(handler(i), 800);
}

Demo

答案 3 :(得分:-2)

setTimeout接受变量作为附加参数:

setTimeout(function(a, b, c) {
    console.log(a, b, c);
  }, 1000, 'a', 'b', 'c');

Source

编辑:在您的示例中,i的有效值可能是8,因为该函数仅在循环结束后被调用。您需要为每次调用传递i的当前值:

var end=8;
for (var i = 1; i < end; i ++) {
  setTimeout(function (i) {
      console.log(i);   
   }, 800, i);
}