How to nest loops to cycle through indexed array inside of associative array (JS)
I've got an indexed array of urls nested inside of another array that uses strings as its keys. I need to extract information from both arrays and I'm using the following loops.
// Loop through the elements in the associative level to get a count of its items
var keyCnt = 0;
for(key in serviceCategories) {
keyCnt++;
}
// Then loop through it again, this time nesting another for loop to get at the inner/indexed arrays
for(key in serviceCategories) {
var currCat = key;
for (var i = 0; i < keyCnt; i++) {
$.ajax({
url: serviceCategories[currCat][i],
success: function(data) {开发者_开发技巧
parsePageCont (data, currCat);
}
});
}
}
}
This code works ok for the first element of the first array. It cycles through its inner array and excecutes the ajax call for every url with no problem. But then, when it finishes with the first element of the first array it doesn't proceed to the second one and fetch IT'S inner array data.
I hope that explanation wasnt too messed up.
You can see the full code here for more clarity: http://jsfiddle.net/FvP5f/
Assuming your data structure is an object with arrays for properties, you would do it like this.
serviceCategories
has to be an object, not an array. Javascript doesn't have associative arrays. It has objects for storage by key and iteration by key. Arrays indexes are numeric.- You have to actually iterate over the length of each embedded array.
- You can't refer to the
key
variable in the success handler because that gets called long after the loops so it's value has changed. To solve that problem, we put the key in a context object that will get set as the "this" pointer for the success handler so we can get back to the key.
Here's the code to solve those issues:
// assume data is of this structure (where I've shown numbers here, they are actually URLs)
serviceCategories = {
houses: [1,2,3,4],
cottages: [5,6,7,8],
hotels: [8,9,0,1],
apartments: [2,2,3,4,5,7,8,9]
};
for (key in serviceCategories) {
if (serviceCategories.hasOwnProperty(key)) {
var array = serviceCategories[key];
// got the next array, iterate through it
for (var i = 0; i < array.length; i++) {
var context = {};
$.ajax({
url: array[i],
context: {key: key}, // can't refer to key in success handler, so we sest it as context
success: function(data) {
parsePageCont(data, this.key);
}
}
});
}
}
Well, one problem seems to be that you are assuming that the second dimension of your array is always the same size (ie keyCnt). You also seem to be counting the wrong direction, by which i mean you would get two (inGoodHands and spaRituals), while you are using it for the second index which is 2 for inGoodHands, and 3 for spaRituals)).
It seems like you should be doing something like this:
for(x in serviceCategories) {
for(y in serviceCategories[x]) {
call ajax for serviceCategories[x][y]
}
}
Javascript scope is the function, not the block. While you can put var curcat
inside a for loop it's important to understand that you are not creating a different variable for each iteration.
This means that all the closures you are creating in the loop will actually be based on the same variable so what you probably observed is not that only the first works, but that all of them worked by they were all working on the last key.
The solution for creating a local scope in javascript is to use a local function; instead of
(function(data){ parsePageCount(data, curcat); })
you could use
(function(x){return function(data){ parsePageCount(data, x); };})(curcat)
where the name x
has been used instead of curcat
to make clear the distinction.
This variable will be indeed separate for each of the created closures.
精彩评论