$ vs. $_

JavaScript performance comparison

Test case created by Kyle Simpson

Info

Experimenting with a $_(..) as a super-fast single element collection wrapper'er for jQuery, as opposed to the slower $(..). Kinda like Ext.fly(), I think.

CAUTION: this implementation of $_(..) can only be used once at a time, meaning you can't wrap two different objects in the same code block and use them both simultaneously. You can use it as many times as you like, just you must be done with one use of it before going onto the next use of it.

For instance...

// ok:

$('a').each(function(){ $_(this).attr(...); $_(another).css(...) });

// NOT ok:

$('a').each(function(){ var a = $_(this), b = $_(another); a.attr(...)+b.attr(...); });

Preparation code

<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a> <a href="#">test</a>

<script>
  (function($) {
   var tmp = $(1);
   window.$_ = function(el) {
    tmp.context = tmp[0] = el;
    return tmp;
   };
  })(jQuery);
</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
$(...) wrapping
$("a").each(function() {
 $(this).attr("href");
});
pending…
$_(...) wrapping
$("a").each(function() {
 $_(this).attr("href");
});
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

7 comments

Gildas commented :

On Chrome (not tested on other browsers), this code does not work:

$("a").each(function() { console.log($_(this).attr("href")); }); It just displays undefined…

Kyle Simpson (revision owner) commented :

Gildas--- you're quite correct. I fixed an error in the $_ implementation. But now $_ is slower. Need to figure out a fix. Working on it.

Gildas commented :

@Kyle:

this implementation seems to be a little bit faster : (function($) { var tmp = $([0]); window.$_ = function(el) { var tmp2 = tmp; tmp2.context = tmp2[0] = el; return tmp2; }; })(jQuery);

See here : http://jsperf.com/dollar-vs-dollar-underscore/5

Diego Perini commented :

Maybe adding the corresponding test in plain Javascript/DOM could be relevant:

for (var i = 0, a = document.getElementsByTagName('a'), l = a.length; l > i; ++i)
  a[i].getAttribute('href');

Kyle Simpson (revision owner) commented :

Gildas -- ok, fixed it (even simpler than your /5 revision...but both your's and mine have an important caveat, that i've added to the description above... since it's basically "sharing" the collection object across multiple calls to $_(...), you have to be careful not to use two calls to it simultaneously. You can of course call it multiple times, but you have to be done with the usage of the first call's return value before moving on. Otherwise, the second call will clobber the first's value.

Kyle Simpson (revision owner) commented :

Diego- while your suggestion is technically accurate, it misses the point of the original test. the original test assumes that you want/need all the jquery helpers wrapped around a single element, and what the fastest way to get that is. of course, almost any non-jquery equiv is gonna be faster, but that's irrelevant for comparing two approaches in jQuery.

Diego Perini commented :

Kyle my point was not about Javascript being faster than jQuery, that's a known fact, I said "maybe relevant" because what your code does is creating an alternative entry point in jQuery that skips all the conditional checks in the original wrapper. At this point if the final goal is speed why not use a snippet of code side by side with the framework instead of following the same philosophy of wrapping a single element (and extend it with every helper available) even if it is not necessary ?

In the end what is going to happen is just a call to ".getAttribute()" (at best). No much magic there.

However, as you said, the objective was different, so to remain in line with jQuery coding I would suggest trying:

$("a").each(function() { $.fn.attr.call([this], 'href'); });

if this is faster the bonus is that it will remain compatible with current jQuery coding practices with no other limitations.

It doesn't pass a real jQuery object, just an array. I haven't tried this with any other method but should work with most of them.

Add a comment