Reputation: 99
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);
};
I'm calling a function with callback inside a for-loop. The callback function need to access the current loop's iteration i. I'm coming up with the solution above.
Is there any other way to do things like this?
Upvotes: 3
Views: 272
Reputation:
What you're doing is not unreasonable and should work fine. Purely at the level of readability, I might go with
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));
};
If you are comfortable using 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));
}
We bind the first argument to i
, resulting in a "curried" function taking the term
and def
arguments.
Then of course there is this horrible hack, do not try this at home.
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};
});
}
}
Upvotes: 2
Reputation: 3596
It seems as though you basically wish to
To set up the properties you need you might do something like this ..
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]};
})
Now you need a way to access any term in any quiz. So you could do that with a function such as ..
function getTerm(qn, tn){
return myApp.quiz[qn].terms[tn];
}
var q0t2 = getTerm(0, 2);
console.log(q0t2); // def: "about css", term: "css"
I am not so sure just what your needs are here, but this is my best guess. Please elaborate if your situation does not fit the sort of methods I am using here. :)
Upvotes: 1
Reputation: 28718
The structure inside the loop is called Immediately-Invoked Function Expression (IIFE).
IIFEs can be useful for example when you create event handlers in a cycle, and would like to lock the current value of the loop variable for each event handler for later use. This "locking" is called (lexical or function) closure: the lexical scope of the outer function (in your case, the IIFE), including any constants, local variables and argument values (in your case, the num
argument of the IIFE, which is the actual value of the loop variable), become part of the internal state of each inner function object (in your case, the callback function passed to myApp.getTerm
), even after execution of the outer function (the IIFE) concludes.
So I think you do this right, using an IIFE is a perfectly valid solution in your case.
An intersting example of this pattern (IIFE for closure) can be found in John Resig's implementation of inheritance:
// ...
(function(name, fn){
return function() {
// use name and fn here
};
})(name, prop[name])
// ...
Upvotes: 1
Reputation: 69964
Most of the time I use iteration functions instead of bulidtin loops. They are available in newer browsers and most JS libraries:
array.forEach(function(item, i){
//We can freely use "item" and "i" in callbacks without worrying
setTimeout( function(){ console.log(item, i) }, 1000 );
});
This it is usually shorter the the for-loop version (if you are iterating over an array at least) and it avoids the closures-in-for-loops bug for "free", without having to add extra imediately invoked functions or things like that.
The major downside of this method is that it doesn't support using the "this" and using break, continue and return statements as well as the builtin loops and that most libraries come with only functions for array or dictionary iteration, without support for more general loop styles. While I rarelly end up needing this kind of advanced functionality, when it does come up I usually just use extra closures (like you did) or, if it is a common pattern, write my own iterator functions.
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] = { ... }
});
});
Upvotes: 1
Reputation: 50205
It's more readable to define a named function to call:
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);
};
Other than that, I don't know what you can do.
Upvotes: 2