Skip to content

Instantly share code, notes, and snippets.

@Striker21
Forked from padolsey/gist:500145
Created November 9, 2011 20:57
Show Gist options
  • Save Striker21/1352993 to your computer and use it in GitHub Desktop.
Save Striker21/1352993 to your computer and use it in GitHub Desktop.
quickEach
// $.quickEach() replicates the functionality of $.each() but allows 'this'
// to be used as a jQuery object without the need to wrap it using '$(this)'.
// The performance boost comes from internally recycling a single jQuery
// object instead of wrapping each iteration in a brand new one.
// Development -----------------------------------
(function($)
{
$.fn.quickEach = function(f)
{
var j = $([0]), i = -1, l = this.length, c;
while(
++i < l
&& (c = j[0] = this[i])
&& f.call(j, i, c) !== false
);
return this;
};
})(jQuery);
// Minified --------------------------------------
(function($){$.fn.quickEach=function(f){var j=$([0]),i=-1,l=this.length,c;while(++i<l&&(c=j[0]=this[i])&&f.call(j,i,c)!==false);return this}})(jQuery);
// Usage -----------------------------------------
(function($)
{
$('div').quickEach(function(i, el)
{
//'this' is a jQuery object
//'i' is the index
//'el' is the DOM element
//Print the index of each element
this.html('Index: '+i);
});
})(jQuery);
@Striker21
Copy link
Author

Thanks creage. Your performance test says mine is fastest :)

@creage
Copy link

creage commented Mar 31, 2012

I'm really surprised about the difference for IE - only 4x. But coming to Chrome - it just blows up :)

@creage
Copy link

creage commented Apr 1, 2012

Yesterday I've included this gist in my production code, and faces with an issue of undefined .context property of jQuery object representing iterated element. So you'd need to update you code on line 14 like that "(j.context = j[0] = this[i])".

Apart of that, I think it's better to have default context while we'are in loop, same as jQuery does, meaning "this" should point to DOM element, and first argument should be index, and second should be our jQuery element - what do you think?

@Striker21
Copy link
Author

Try the above code and see if the problem is fixed.

Also, I disagree with the idea of 'this' pointing to the DOM element. You run $.quickEach() on a jQuery collection, so it makes sense (to me, at least) that 'this' is a jQuery object.

@creage
Copy link

creage commented Apr 7, 2012

Hi again.

Well, after about a week of using, I found another issue, which seems like unsolvable. The issue is that whenever you'd like to save a reference to some element being iterated using quickEach, after the loop is ended, all of references you saved, will have pointer to the last element in the collection. It's because of j[0] = this[i].

The only way to avoid that, is use native .each() method. Sad, but true.

Any ideas how to solve that?

@Striker21
Copy link
Author

No, there is no way around that problem because you're saving a reference to the jQuery object which is recycled for every iteration. The solution would be not to save a reference to the jQuery object, but to the element's node.
This can be done two ways, which I've combined into one code snippet

var i;
var foo = [];
var bar = [];
$('div').quickEach(function(i, e)
{
    foo.push(this[0]); /* Method 1 */
    bar.push(e); /* Method 2 */
});
for(i in foo)
    $(foo[i]).html(i);
for(i in bar)
    $(bar[i]).html(i);

@creage
Copy link

creage commented Apr 7, 2012

Yeah, but when you'll need your reference later, you still will be forced to wrap it into jQuery. Which, actually wraps our element twice (or one and a half), while in .each() it wraps it once only - right?.

But, again, I like your point, that we shouldn't reference to the jQuery object, but to the element itself. Meaning if we need to iterate a collection fast - we use .quickEach without actually wrapping each element. If we'll need any element later - we'll wrap it manually. Thanks for that tip :)

@Striker21
Copy link
Author

You are correct. If you plan on referencing one of the objects again you will need to wrap it if you plan on using jQuery functions on it. In that scenario, you may be better off using standard $.each().
However, if you're storing a reference to the entire collection, then quickEach is still the better option. This is what you'd do:

var myCollection = $('div'); //You now have a variable referencing all of the divs

myCollection.quickEach(function(i, e)
{
    /* Do stuff */
});

//Later on, do stuff to the same collection
myCollection.quickEach(function(i, e)
{
    /* Do more stuff */
});

/* Do even more stuff */
myCollection.addClass('foo');

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment