Bug Tracker

Opened 14 years ago

Closed 13 years ago

Last modified 11 years ago

#5499 closed enhancement (wontfix)

jQuery.each

Reported by: dbjdbj Owned by:
Priority: low Milestone: 1.5
Component: core Version: 1.3.2
Keywords: foreach Cc:
Blocked by: Blocking:

Description

Can we please make jQuery more robust by using hasOwnProperty to check each item in the jQuery.each loop to be sure it belongs to the object itself:

1 forEach = function(obj, f) { 2 for (var key in obj) { 3 if (obj.hasOwnProperty(key)) { 4 f.call(obj, obj[key], key); 5 } 6 } 7 };

I know this might slow jQuery down.

Regards: DBJ

Change History (15)

comment:1 Changed 14 years ago by dbjdbj

<code> 1 forEach = function(obj, f) { 2 for (var key in obj) { 3 if (obj.hasOwnProperty(key)) { 4 f.call(obj, obj[key], key); 5 } 6 } 7 }; </code>

comment:2 Changed 14 years ago by dbjdbj

 1 forEach = function(obj, f) { 
 2  for (var key in obj) { 
 3   if (obj.hasOwnProperty(key)) { 
 4    f.call(obj, obj[key], key); 
 5   } 
 6  } 
 7 }; 

comment:3 Changed 14 years ago by dbjdbj

Please see : <code> http://github.com/DBJDBJ/jquery/blob/master/speed/dbj.each.js http://github.com/DBJDBJ/jquery/blob/master/speed/dbj.each.htm </code> It appears the speed difference might not be that bad. Slightly slower, but more robust? This requires a lot more testing. --DBJ

comment:4 Changed 14 years ago by dbjdbj

I added this version in my fork:

// Ticket#5499  ---> use hasOwnProperty()
each: function( object, callback, args ) {
var name, length = object.length, value;
if (length === undefined || jQuery.isFunction(object)) {
    if (args) {
        for (name in object) {
         if (hasOwnProperty.call(object,name) && (callback.apply(object[name], args) === false)) break;
        }
    } else {
       for (name in object) {
            if (hasOwnProperty.call(object,name) && callback.call(value = object[name], name, value) === false)) break;
        }
    }
} else {
    if (args) {
        while (length-- && (callback.apply(object[length], args) !== false));
    } else {
        while (length-- && (callback.call(value = object[length], length, value) !== false));
    }
}
return object;
},

Any comments?

--DBJ

comment:5 Changed 14 years ago by dbjdbj

I think I would like to change the logic of each() ? Fiddling with the ticket #5554, made me think. If each() would do only arrays as arrays, that is using lemgth, and "everything" else with for/in loop what dould happend then? What I mean is what if each() would look like this :

// Ticket#5499  ---> use hasOwnProperty()
// also just divide on isArray()
each: function( object, callback, args ) {
var name, value;
if ( ! jQuery.isArray(object)) {
    if (args) {
        for (name in object) {
         if (hasOwnProperty.call(object,name) && (callback.apply(object[name], args) === false)) break;
        }
    } else {
       for (name in object) {
            if (hasOwnProperty.call(object,name) && callback.call(value = object[name], name, value) === false)) break;
        }
    }
} else {
var length = object.length ;
    if (args) {
        while (length-- && (callback.apply(object[length], args) !== false));
    } else {
        while (length-- && (callback.call(value = object[length], length, value) !== false));
    }
}
return object;
},

Above will not iterate over jQuery instance using its length property. But is that an issue? jQuery is an object and for/in above , will iterate over its "stack" properly.

comment:6 Changed 14 years ago by dbjdbj

After few days (!), and several false commits, I think I am finally satisfied with the state of affairs in my core.js ( http://github.com/DBJDBJ/jquery/blob/master/src/core.js ) This is really a non-trivial change and involves merge(), grep(), map(), makeArray() as users of this. Testing and revieweing by the core team , I think, might be required here.

Thanks: Dusan

comment:7 Changed 13 years ago by dbjdbj

Now, I realize it will be never feasible to try and improve jQuery.each(). It is way non-standard. It uses non ES5 callbacks and it uses "args" arguments which is also not part of ES5 callback footprint. It also can iterate over function arguments. It is not feasible to "improve" it by using (native or not) Array.forEach, Object.keys, etc ... It is much more feasible to develop jQuery.forEach( object, callback ), which will be built upon ES5 iteration and callbacks concepts. object type/class in this instance may be : array, object, string. And even number , or DOM node. Internally it would use native or not, ES5 Array iteration methods. And yes it might or might not take in (while iterating) properties which are not "owned" by the object.

jQuery.forEach( object, callback, use_only_own_properties ) {

use_only_own_properties = use_only_own_properties
true ;

}

Thanks: DBJ

comment:8 Changed 13 years ago by Rick Waldron

.hasOwnProperty(key) lookups are too costly for realistic addition to $.each()

comment:9 Changed 13 years ago by Rick Waldron

Resolution: wontfix
Status: newclosed

comment:10 Changed 13 years ago by Rick Waldron

Milestone: 1.3.2
Resolution: wontfix
Status: closedreopened

comment:11 Changed 13 years ago by Rick Waldron

Milestone: 1.5
Priority: majorlow

comment:12 Changed 13 years ago by Rick Waldron

Will create a patch and perf tests to see if there is any benefit.

comment:13 Changed 13 years ago by dbjdbj@…

I can't believe this was 11 months ago ? Thanks for looking into this again.

Benefit(s) I think are purely in conformance to ES5. jQuery.forEach() would deliver that. In the same time making jQuery.each() a candidate for deprecation. A real can of worms, I think we all agree.

--DBJ

comment:14 Changed 13 years ago by snover

Resolution: wontfix
Status: reopenedclosed

There is potentially a benefit to allowing people to enumerate the prototype’s properties as well; if we forcibly filter it away, then nobody gets that benefit. If someone really needs to filter, they can do it in their callback.

comment:15 Changed 11 years ago by sun

Other frameworks are automatically filtering by hasOwnProperty() in their loop helpers.

This change would vastly help projects like Drupal, which can be extended in unlimited ways and potentially loading any kind of externally developed JavaScript - whereas extending prototypes is considered bad practice within Drupal itself, so its core code does not necessarily account for the possibility.

allowing people to enumerate the prototype’s properties as well

That sounds like an extreme edge-case, for which developers can still use a custom for...in loop?

Alternatively, I don't see

1) why this couldn't be a function argument (shifting the internal args), or

2) why there couldn't be a .eachOwn()?

Version 0, edited 11 years ago by sun (next)
Note: See TracTickets for help on using tickets.