Bug Tracker

Modify

Ticket #5499 (closed enhancement: wontfix)

Opened 4 years ago

Last modified 2 years ago

jQuery.each

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

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

comment:1 Changed 4 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 4 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 4 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 4 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 4 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 4 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 4 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 3 years ago by rwaldron

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

comment:9 Changed 3 years ago by rwaldron

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

comment:10 Changed 3 years ago by rwaldron

  • Status changed from closed to reopened
  • Resolution wontfix deleted
  • Milestone 1.3.2 deleted

comment:11 Changed 3 years ago by rwaldron

  • Priority changed from major to low
  • Milestone set to 1.5

comment:12 Changed 3 years ago by rwaldron

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

comment:13 Changed 3 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 3 years ago by snover

  • Status changed from reopened to closed
  • Resolution set to wontfix

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 2 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()?

EDIT: Related:  https://github.com/jquery/sizzle/issues/21

Last edited 2 years ago by sun (previous) (diff)

Please follow the  bug reporting guidlines and use  jsFiddle when providing test cases and demonstrations instead of pasting the code in the ticket.

View

Add a comment

Modify Ticket

Action
as closed
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.