简体   繁体   中英

In JavaScript, when looping through a FOR loop, how do I pass the value of the item in an array to an anonymous function?

In JavaScript, I need to loop through a for loop to get the value of an item in an array, and pass this to an anonymous function. A simplified example of this is below:

var aFunctions = []; 
var aStrings = ["a","b","c"];
for (var i = 0; i < aStrings.length - 1; i++) {
    aFunctions[i] = function () { alert(aStrings[i]); };
}
aFunctions[0](); //alerts "c" instead of "a"

I can see why this is happening - the variable i is being set to 2 when the loop exits, and then when I call aFunctions[0]() , the function fires off and evaluates aStrings[i] rather than aStrings[0] .

What I want to know is how to get the value of aStrings[i] returned within my for loop, and not when it's executed.


To give more specific detail, I'm working on a Google Maps page, and the markers are stored in a JavaScript array client-side, and in a DB server-side. I write the array at page-load and after that's complete I want to generate the markers, and give them each a custom InfoWindow with the text set to an HTML string. This is the specific code I use:

for (var i = 0; i < tGoogleMarker.length - 1; i++) {
    var text = tGoogleMarker[i][4];
    var marker = new google.maps.Marker({
                        position: new google.maps.LatLng(tGoogleMarker[i][0], tGoogleMarker[i][1]),
                        map: map,
                        flat: false,
                        icon: tGoogleMarker[i][2],
                        shadow: tGoogleMarker[i][3]
                        });
    google.maps.event.addListener(marker, 'click', function () { ShowMarkerContentPopUp(this, text); });
}

Instead of getting the HTML string of the specific marker, I get the text of the last item in the array used for all markers.

You need to use closure. Read More about this here: How do JavaScript closures work?

 var aFunctions = []; var aStrings = ["a","b","c"]; for (var i = 0; i < aStrings.length - 1; i++) { aFunctions[i] = (function(val){ return function() { alert(val) } })(aStrings[i]); } aFunctions[0](); //alerts "c" instead of "a" 

You can use a closure around the addListener part:

(function(text){
    google.maps.event.addListener(marker, 'click', function () { ShowMarkerContentPopUp(this, text); });
})(text);

This creates a new scope and takes the text variable as an argument. It means the text inside the closure is protected from being changed outside of the closure.

The same can be done to solve your first example:

for (var i = 0; i < aStrings.length - 1; i++) {
    (function(i){
        aFunctions[i] = function () { alert(aStrings[i]); };
    })(i);
}

More info on closures:

var aFunctions = []; 
var aStrings = ["a","b","c"];
for (var i = 0; i < aStrings.length; i++) {
    aFunctions[i] =  (function(arg) { return function() { alert(arg); };})(aStrings[i]) ;
}
aFunctions[0](); // alerts "a"
aFunctions[2](); // alerts "c"

http://jsfiddle.net/dbtncehf/

Well, you can avoid needing to worry about closures much and still achieve the necessary results. It can be done by attaching each text variable to its respective marker. This way your anonymous function can call it using this.text

for (var i = 0; i < tGoogleMarker.length - 1; i++) {
var marker = new google.maps.Marker({
                    text: tGoogleMarker[i][4],
                    position: new google.maps.LatLng(tGoogleMarker[i][0], tGoogleMarker[i][1]),
                    map: map,
                    flat: false,
                    icon: tGoogleMarker[i][2],
                    shadow: tGoogleMarker[i][3]
                    });
google.maps.event.addListener(marker, 'click', function () { ShowMarkerContentPopUp(this, this.text); });

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM