Bug Tracker

Ticket #7260 (closed bug: invalid)

Opened 4 years ago

Last modified 2 years ago

$.each() fails on an object when the object has a key named 'length'

Reported by: lucas.madar@… Owned by:
Priority: undecided Milestone: 1.5
Component: unfiled Version: 1.4.2
Keywords: Cc:
Blocking: Blocked by:

Description

If you have an object, like this:

var obj = { name: "something", length: 12, height: 32 };

and then you try to iterate over it using $.each:

$.each( obj, function( key, value ) {
    ...
} );

The inner function is never called because jquery treats the object as an array instead of an object. This behavior is unexpected; it should either be documented or fixed.

Change History

comment:1 Changed 4 years ago by jitter

I think you misread the documentation. $.each behaves exactly as expected and as documented.

From  http://api.jquery.com/jQuery.each/

Arrays and array-like objects with a length property (such as a function's arguments object) are iterated by numeric index, from 0 to length-1. Other objects are iterated via their named properties.

This sentence covers your case, stating that objects with a length property (as in your example) are iterated by numeric index.

So if you remove/name the length property in your sample object $.each while behave as expected.

Here a  live test case to show what is happening.

Version 0, edited 4 years ago by jitter (next)

comment:2 Changed 4 years ago by snover

  • Status changed from new to closed
  • Resolution set to invalid

comment:3 Changed 4 years ago by anonymous

I fail to see how a json object with a quoted length property could be considered an array-like object.

comment:4 Changed 4 years ago by anonymous

This is also a problem in jQuery templates when using {{each}} to iterate through an object which happens to have a "length" key.

comment:5 Changed 4 years ago by jboesch

I think we can fix this issue. If jQuery.map is supporting objects in 1.6 (and works with length props) I think we should maybe consider adding it here.

Here is what the code is right now being used in jQuery.each (object/array detection):

isObj = length === undefined || jQuery.isFunction( object );

This can be changed to what's being used in jQuery.map (v 1.6):

isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || jQuery.isArray( elems ) ) ;

Here's Dan's isArray var in action in the jQuery.map function:  https://github.com/jquery/jquery/pull/299/files

Here's a fiddle with me changing that one line:  http://jsfiddle.net/jboesch26/Ungsa/

This would allow looping over objects with length props. This newEach2 proposal seems to be slightly faster as well:  http://jsperf.com/each-object-supporting-length-key/6

If this is cool, I'll make a pull request.

Last edited 4 years ago by jboesch (previous) (diff)

comment:6 Changed 4 years ago by jboesch

Last edited 4 years ago by jboesch (previous) (diff)

comment:7 Changed 3 years ago by sindresorhus

#11573 is a duplicate of this ticket.

comment:8 Changed 3 years ago by dmethvin

#11810 is a duplicate of this ticket.

comment:9 Changed 2 years ago by dmethvin

#12130 is a duplicate of this ticket.

Note: See TracTickets for help on using tickets.