JavaScript:有没有更好的方法来使用回调函数进行for循环?

时间:2012-06-23 00:48:07

标签: javascript callback

for(var i=1; i<496; i++) {
    (function(num) {
        myApp.getTerm(num, function (term, def){
            myApp.quizlet[0].terms[num] = { term: term, definition: def};
        });         
    })(i);
};

我正在调用for循环中的回调函数。 回调函数需要访问当前循环的迭代i 。我想出上面的解决方案。

有没有其他办法可以做这样的事情?

5 个答案:

答案 0 :(得分:2)

定义要调用的命名函数更具可读性:

myApp.getTermForQuizzlet = function(num){
    myApp.getTerm(num, function (term, def){
        myApp.quizlet[0].terms[num] = { term: term, definition: def };
    });         
};

for(var i=1; i<496; i++) {
    myApp.getTermForQuizzlet(i);
};

除此之外,我不知道你能做什么。

答案 1 :(得分:2)

你所做的并非不合理,应该可以正常工作。纯粹在可读性方面,我可能会选择

for(var i=1; i<496; i++) {
    function get_callback(n) {
        return function(term, def) {
            myApp.quizlet[0].terms[n] = { term: term, definition: def};
         };
    }
    myApp.getTerm(i, get_callback(i));         
};

如果您习惯使用Function.bind:

function callback (n, term, def) {
    myApp.quizlet[0].terms[n] = { term: term, definition: def};
}
for(var i=1; i<496; i++) {
    myApp.getTerm(i, callback.bind(this,i));
}

我们将第一个参数绑定到i,从而产生一个带有termdef参数的“curried”函数。

然后当然有这个可怕的黑客,不要在家里试试。

for(var i=1; i<496; i++) {
    try { throw i; }
    catch (i) {
        myApp.getTerm(i, function (term,def) {
             myApp.quizlet[0].terms[i] = { term: term, definition: def};
        });
    }
}

答案 2 :(得分:1)

循环内部的结构称为Immediately-Invoked Function Expression(IIFE)。

例如,在循环中创建事件处理程序时,IIFE可能很有用,并且希望锁定每个事件处理程序的循环变量的当前值以供以后使用。这个“锁定”被称为(lexical or function) closure:外部函数的词法范围(在您的情况下,IIFE),包括任何常量,局部变量和参数值(在您的情况下,num参数IIFE,它是循环变量的实际值),即使在执行外部函数之后,也成为每个内部函数对象(在您的情况下,传递给myApp.getTerm的回调函数)的内部状态的一部分( IIFE)总结。

所以我认为你这样做是正确的,在你的情况下使用IIFE是一个非常有效的解决方案。

可以在John Resig's implementation of inheritance中找到这种模式(IIFE用于结束)的有趣例子:

// ...
(function(name, fn){
  return function() {
    // use name and fn here
  };
})(name, prop[name])
// ...

答案 3 :(得分:1)

大多数时候我使用迭代函数而不是bulidtin循环。它们适用于较新的浏览器和大多数JS库:

array.forEach(function(item, i){
    //We can freely use "item" and "i" in callbacks without worrying
    setTimeout( function(){ console.log(item, i) }, 1000 );
});

这通常比for循环版本更短(如果你至少迭代一个数组)并且它避免了“free”中的for-for-for循环错误,而不必添加额外的临时调用函数或类似的东西。

这种方法的主要缺点是它不支持使用“this”并使用break,continue和return语句以及内置循环,并且大多数库只带有数组或字典迭代的函数,没有支持更通用的循环样式。虽然我最终需要这种高级功能,但当它确实出现时,我通常只使用额外的闭包(就像你做的那样),或者,如果它是一个常见的模式,编写我自己的迭代器函数。

var forLoop = function(i0, n, f){
    for(var i=i0; i<n; i++){
        f(i);
    }
};

forLoop(1, 496, function(i){
    myApp.getTerm(i, function(term, def){
        myApp.quizlet[0].terms[i] = { ... }
    });
});

答案 4 :(得分:1)

好像你基本上希望

  1. 创建app,myApp;
  2. 将属性.quiz添加到myApp;
  3. 将属性.terms添加到.quiz;
  4. 对于测验中的每个术语,形成一个对象,将每个术语与其定义联系起来。
  5. 要设置您需要的属性,您可以执行以下操作..

    var terms = ['js', 'php', 'css', 'html', 'as3'];
    var defin = ['about js', 'about php', 'about css', 'about html', 'about as3'];
    var myApp = {};
    myApp.quiz = new Array;
    myApp.quiz[0] = [];
    myApp.quiz[0].terms = new Array;
    
    terms.forEach(function(ele, idx){
        myApp.quiz[0].terms[idx] = {term: terms[idx], def: defin[idx]};
    })
    

    现在您需要一种方法来访问任何测验中的任何术语。所以你可以使用像......这样的函数来做到这一点。

    function getTerm(qn, tn){
      return myApp.quiz[qn].terms[tn];
    }
    var q0t2 = getTerm(0, 2);
    console.log(q0t2); // def: "about css", term: "css"
    

    我不太确定你的需求是什么,但这是我最好的猜测。 请详细说明您的情况是否与我在这里使用的方法不符。 :)