1

I have a loop that calls a function thrice with different parameters using different timeout intervals:

<script type="text/javascript">
    var myArray = [];

    for (i=0; i<3; i++) {
        myArray[i] = [];
        myArray[i]['second'] = (1+i)*3000;
        myArray[i]['valeur'] = i+i;

        setTimeout(function() {
            otherfunction(myArray[i]['valeur']);
        }, myArray[i]['second']);
    }

    function otherfunction(data1) {
        console.log(data1);
    }
</script>

The script correctly calls otherfunction() but there's an error:

Uncaught TypeError: Cannot read property 'valeur' of undefined

how do I solve this problem. Looks like a problem concerning variable scope.

Matthew Layton
  • 39,871
  • 52
  • 185
  • 313
Charlie
  • 25
  • 4

2 Answers2

4

change it like:

for (i=0; i<3; i++)
{

    myArray[i] = new Array();
    myArray[i]['second'] = (1+i)*3000;
    myArray[i]['valeur'] = i+i;


    var timeoutCallback = (function(valeur){
        return function(){
            otherfunction(valeur);
        }
    })(myArray[i]['valeur']);

    setTimeout(timeoutCallback, myArray[i]['second']);


}

The point here is using JavaScript closures to keep the current value of a variable in a scope, for your callback like functions.

As you see we have 2 nested function here, first one creates a safe scope to keep your current value of myArray[i]['valeur'], which totally depends on variable i, which in your for loop doesn't have a fixed value.

For more information about check this question out, this has the most valuable answers ever:

How do JavaScript closures work?

Community
  • 1
  • 1
Mehran Hatami
  • 12,723
  • 6
  • 28
  • 35
0

That's because in the timeout functions the

i

variable is already 3, and your array length is 3 so myArray[3] is undefined. You need to make sure that the functions passed to setTimeout have a closure on the proper value.

This will work:

var myArray = new Array();

for (i=0; i<3; i++)
{

    myArray[i] = new Array();
    myArray[i]['second'] = (1+i)*3000;
    myArray[i]['valeur'] = i+i;



    (function(val){
        setTimeout(function() 
        {
            otherfunction(val);
        },myArray[i]['second']);
    })(myArray[i]['valeur']);
}


function otherfunction(data1)
{
    console.log(data1);
}
kamilkp
  • 9,690
  • 6
  • 37
  • 56