views:

395

answers:

1

Have been struggling with Javascript closure for a while trying to wrap brain around function scopes, but I think they're wrapping around me instead. I've looked at a number of posts (Nyman's was the most helpful) but obviously still don't get it. Trying to run a loop over the hover method in jQuery. Need hover functions to ultimate trigger more than one action each, but would be happy to get them working with a single image swap each for now.

$(document).ready(function() {

    imageSource = []; 
    imageSource[0] = 'images/img0.png'  //load 0 position with "empty" png
    imgArea = [];

    for (var i=1; i<11; i++) {

     (function( ){  //anonymous function for scope

      imageSource[i] = 'images/img' + i + '.png';
      imgArea[i] = '#areamap_Img' + i;

      // running console.log here gives expected values for both

      $(imgArea[i]).hover(   //imgArea[i] (selector) works correctly here

       function() {
        $('#imgSwap').attr('src',imageSource[i]);  // imageSource[i] is undefined here
       },
       function() {
        $('#imgSwap').attr('src','images/img0.png');
       });

     })(); // end anonymous function and execute

    }; // for loop

});

Tried the idea of using an anonymous function for scoping from another jQuery post. Seems to work OK but throws an undefined for the array value in the first hover function, I guess because it's an inside function (hardcoded image sources work correctly there).

+8  A: 

There is indeed a problem with your closures, and it has to do with your usage of the var i. Since your anonymous function has no local version of i, it's using the version of the function above it. However, when it tries to access i at a later date, i == 11 (since that's what made the loop terminate). To fix this, you need to declare a local version of i in each anonymous function, like this:

for (var i=1; i<11; i++) {

    (function( ){  //anonymous function for scope                
            var index = i; // The important part!

            // It's not technically necessary to use 'index' here, but for good measure...
            imageSource[index] = 'images/img' + index + '.png';
            imgArea[index] = '#areamap_Img' + index;

            $(imgArea[index]).hover(

                    function() {
                            $('#imgSwap').attr('src',imageSource[index]);  // Here's where `index` is necesssary.
                    },
                    function() {
                            $('#imgSwap').attr('src','images/img0.png');
                    });

    })(); // end anonymous function and execute

}; // for loop

Additionally, there's a small problem in your code you should fix just for good measure. You're not accessing your local variables correctly; you should use:

var imageSource = []; 
var imageSource[0] = 'images/img0.png'  //load 0 position with "empty" png
var imgArea = []

Without the "var", you're declaring and accessing global variables. (If this is your intended behavior then I apologize.)

Daniel Lew
Thank you!! I've found understanding how these things iterate to be very difficult, this is a very helpful explanation.
boomturn