【问题标题】:Passing parameters into a closure for setTimeout将参数传递给 setTimeout 的闭包
【发布时间】:2012-06-01 18:23:16
【问题描述】:

我遇到了一个问题,即我的应用位于 iframe 中,并且是从外部域调用的。当 iframe 正确加载时,IE9 不会触发 load 事件,所以我认为我无法使用 setTimeout 来轮询页面。

无论如何,我想看看我的 setTimeout 完成通常需要多长时间,所以我希望能够记录 setTimeout 从我的回调中触发的延迟,但我不确定如何将该上下文传递给它所以我可以记录它。

App.readyIE9 = function() {
  var timings = [1,250,500,750,1000,1500,2000,3000];    
  for(var i = 0; i < timings.length; i++) {
    var func = function() {
    if(App.ready_loaded) return;
      console.log(timings[i]);
      App.readyCallBack();
    };
    setTimeout(func,timings[i]);
  }
};

我不断收到 LOG: undefined in IE9's console.

实现此目的的正确方法是什么?

谢谢

【问题讨论】:

  • 如果你让它更通用,这可能是一个更好的问题,例如从timing 和所有带有App 的行中删除这么多值!

标签: javascript jquery internet-explorer-9 closures document-ready


【解决方案1】:

发生这种情况是因为您没有在func 中关闭i 的值。循环完成后,i 为 8 (timings.length),数组中不存在。

你需要做这样的事情:

App.readyIE9 = function() {
  var timings = [1,250,500,750,1000,1500,2000,3000];    
  for(var i = 0; i < timings.length; i++) {
    var func = function(x) {
      return function(){
          if(App.ready_loaded) return;
          console.log(timings[x]);
          App.readyCallBack();
      };
    };
    setTimeout(func(i),timings[i]);
  }
};

【讨论】:

  • 谢谢,这正是我想要的。
  • 这重新定义了循环中的函数。 @VisioN 的solution 效率更高。
【解决方案2】:

当您的函数在未来某个时间被setTimeout 调用时,i 的值已经被for 循环增加到其范围的末尾,因此console.log(timings[i]); 报告undefined

要在该函数中使用i,您需要在函数闭包中捕获它。有几种方法可以做到这一点。我建议使用自执行函数来捕获i 的值,如下所示:

App.readyIE9 = function() {
  var timings = [1,250,500,750,1000,1500,2000,3000];    
  for(var i = 0; i < timings.length; i++) {
    (function(index) {
        setTimeout(function() {
            if(App.ready_loaded) return;
            console.log(timings[index]);
            App.readyCallBack();
        }, timings[index]);
    })(i);
  }
};

作为对谁起作用的一点解释:i 被传递给自执行函数作为该函数的第一个参数。第一个参数名为index,并在每次调用自执行函数时冻结,因此for 循环不会导致它在setTimeout 回调被执行之前发生变化。因此,在自执行函数内部引用 index 将获得每个 setTimeout 回调的正确数组索引值。

【讨论】:

    【解决方案3】:

    当您使用 setTimeoutsetInterval 回调时,这是一个常见的问题。您应该将 i 值传递给函数:

    var timings = [1, 250, 500, 750, 1000, 1500, 2000, 3000],
        func = function(i) {
            return function() {
                console.log(timings[i]);
            };
        };
    
    for (var i = 0, len = timings.length; i < len; i++) {
        setTimeout(func(i), timings[i]);
    }
    

    演示: http://jsfiddle.net/r56wu8es/

    【讨论】:

    • 这会以i为参数调用func,并将其返回值传递给setTimeoutfunc 需要返回一个函数。
    • 你没有修复它。 func 仍然返回 undefined
    • 您在原始帖子中遗漏了var func = function(x) {。这就是 Rocket 想要指出的。
    • 是的,该睡觉了 :) 谢谢,伙计们!
    • 这个答案现在与Rocket's answer(参数化函数)基本相同。可以删除吗?
    猜你喜欢
    • 2020-05-15
    • 1970-01-01
    • 2015-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-14
    相关资源
    最近更新 更多