I have an associative array with two object inside. Running this through $(myassoc).each()
, the callback runs only once. Also the callback parameters (index and object) returns 0 and the entire associative array, respectively.
One would expect jQuery.each()
to run for each element in the array, returning the correct keys as index and the correct element as the object.
Why isn't that happening, and can jQuery do what I'm after?
I think you're looking for jQuery.each() instead of .each()
try this:
$.each(myassoc, function(index, value){
//your code
});
try this:
$.each(assocarray,function(i, value){
console.log('index: ' + i + ',value: ' + value);
});
Badly.
Don't $(associative_array).each(function () {...})
-- that's nonsense
Don't $.each(associative_array, function() {...});
-- that has an obscure bug(1)
To see the bug, try this in a javascript console:
> $.each({foo:1, length:-1, bar:2}, console.log)
foo 1
length -1
bar 2
> $.each({foo:1, length:0, bar:2}, console.log)
The first example outputs three lines of key-value pairs, as it should. The second outputs nothing!
The moral of the story, don't use jQuery.each() on objects. (Objects in JavaScript are essentially the same thing as associative arrays.) Things may work fine forever, but you run the risk that someday an object happens to have a member named length
and its value happens to be exactly 0
and then you have a bug out of nowhere that can be very difficult to explain. (I'll let you guess, by the ponderous heft of this answer, whether that ever happened to me.)
As mentioned in the bug report:
If you need to iterate over all keys of objects having the length property, jQuery.each is not the correct solution.
I suggest going further, that jQuery.each should not be relied upon for associative arrays, ever.
(1) This "bug" may never be fixed, since $.each() historically uses Duck Typing on arrays: "Arrays and array-like objects with a length property (such as a function's arguments object) are iterated by numeric index."
Here's what I use[thanks Dominik] to loop through property names and values of objects, or put another way, the keys and values of an associative array:
function looper(object, callback) {
for (var key in object) {
if (object.hasOwnProperty(key)) {
if (false === callback.call(object[key], key, object[key])) {
break;
}
}
}
return object;
}
looper() is then a drop-in replacement for $.each()
> looper({foo:1, length:0, bar:2}, console.log)
foo 1
length 0
bar 2
Just like $.each():
- Inside the callback,
this
is each value
- Inside the callback, returning
false
(not just falsy) terminates the loop
- looper() returns the object originally passed to it
- looper() works on arrays as well as objects.
Use:
var a = [];
looper({foo:1, length:0, bar:2}, function(k, v) {
a.push(k+"="+v);
});
console.assert("foo=1,length=0,bar=2" === a.join());
Try that with $.each() and you'll get an empty result. Because it interprets this particular object as an array-like object of zero length.
The problem is that the $.each()
function internally retrieves and uses the length
property of the passed collection. But in an associative array that has no integer indices the length
always seems to be 0
. For $.each()
now there seems to be nothing to walk through.
The $.each()
function internally retrieves and uses the length
property of the passed collection.
The solutions is simply to use an object instead.
var obj = {
"flammable": "inflammable",
"duh": "no duh"
};
$.each( obj, function( key, value ) {
alert( key + ": " + value );
});