Question

I am making a game using JavaScript and HTML canvas. The 'onload' works perfectly without a for-loop. But 'onload' become buggy and unreasonable in a for-loop. However, I came up with a simple workaround to skip that problem. But I am still curious why. Here comes the codes and how is the workaround:

I have created an object:

function Monster() {
    this.image = new Image();
    this.ready = false;
}

and created to a few (let's say two) instances:

var monster = [];
for(var a = 0; a < 2; a++) {
    monster.push(new Monster());
}

When I tried to initialize these objects, it's gonna fail:

for(n = 0; n < monster.length; n++) { //assume length is 2
    monster[n].image.onload = function() {
        monster[n].ready = true;   /* Problem raise up here, n has the same value as monster.length. 
                                      If length is 2, this line gonna run 2 times */
    };
    monster[n].image.src = 'images/m1.png';
}

However, this problem could be solved easily by creating a function:

for(n = 0; n < monster.length; n++) {
    makeMonster(n);
}

And:

var makeMonster = function(n) {
    monster[n].image.onload = function() {
        monster[n].ready = true;
    };
    monster[n].image.src = 'images/m1.png';
};

The question is, why?

Was it helpful?

Solution

The onload function is async, so by the time it fires the loop has completed and the value of n is whatever it was set to last.

You have to lock the value of the n variable in a new scope with a closure, creating a new function also creates such a scope, or like this

for(n = 0; n < monster.length; n++) {
    (function(k) {
        monster[k].image.onload = function() {
            monster[k].ready = true;
        }
        monster[k].image.src = 'images/m1.png';
     })(n);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top