What is the cost of '$(this)'?

JavascriptJqueryPerformance

Javascript Problem Overview


People here often suggest to cache the jQuery object created from a DOM element, like with this code:

$('#container input').each(function() {
    $(this).addClass('fooClass');
    $(this).attr('data-bar', "bar");
    $(this).css('background-color', 'red');
});
  • Does caching the jQuery object really improve the performance of our code?
  • What happens "behind the scenes" when you pass a DOM element to the jQuery constructor?

Javascript Solutions


Solution 1 - Javascript

In the jQuery tag info this warning appears: > The jQuery function $() is expensive. Calling it repeatedly is extremely inefficient.

Well... that is true only for string selectors, which get parsed with regex to find out what they are:

quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/

Then if the string is a selector (other than id), jQuery traverses the DOM to find a match with its expensive find function:

} else if ( !context || context.jquery ) {
    return ( context || rootjQuery ).find( selector );
}

So yes it's expensive, but that is only true for selectors!

If we pass a DOMElement, the only action jQuery does is saving the DOMElement parameter as the context of the newly created jQuery object and setting the length of the context to 1:

// Handle $(DOMElement)
if ( selector.nodeType ) {
	this.context = this[0] = selector; // Selector here is a DOMElement
	this.length = 1;
	return this;
}

I did some tests with jsPerf, and I found that indeed caching the jQuery object has only a little effect:

Bar chart, described below

In Chrome it's only 7% slower. (In IE it's a little bit more significant: 12%.)

Solution 2 - Javascript

To answer your second question, look at the source:

// Handle $(DOMElement)
if ( selector.nodeType ) {
	this.context = this[0] = selector;
	this.length = 1;
	return this;
}

Solution 3 - Javascript

With regard to the performance difference, if you're looking for a direct comparison between the two, it's helpful to remove any extra code that could skew the result, like DOM selection and other methods that aren't directly related.

http://jsperf.com/this-cost/2

enter image description here

In a more real world setting, the relative difference is minor as your test showed

Another thing to keep in mind is that every time you create a jQuery object, memory needs to be allocated for it, which adds to the work that the garbage collector needs to do.

So I think the reason people suggest caching is from somewhat of a principled standpoint. Extra work is being done that, while it usually won't have a noticeable impact, does ultimately require some overhead that can easily be avoided.

Solution 4 - Javascript

One thing that all of the runtime performance tests here miss is another major consideration:

Network bandwidth.

Caching $(this) into a local variable will generally decrease the size of your script, especially when minified (because this cannot be reduced from four characters).

Consider:

function hello(text) {
    $(this).attr();
    $(this).css();
    $(this).data();
    $(this).click();
    $(this).mouseover();
    $(this).mouseleave();
    $(this).html(text);
}
hello('Hello world');

Closure compiler's minified output is

function hello(a){$(this).attr();$(this).css();$(this).data();$(this).click();$(this).mouseover();$(this).mouseleave();$(this).html(a)}hello("Hello world");

This saves 39 bytes (20%). Now consider:

function hello(name) {
    var $this = $(this);
    $this.attr();
    $this.css();
    $this.data();
    $this.click();
    $this.mouseover();
    $this.mouseleave();
    $this.html(name);
}
hello('Hello world');

The minified output is

function hello(b){var a=$(this);a.attr();a.css();a.data();a.click();a.mouseover();a.mouseleave();a.html(b)}hello("Hello world");

This saves 74 bytes (37%), nearly doubling our byte savings. Obviously, real world savings in large scripts will be lower, but you still stand to gain significant reductions in the size of your script by caching.

Really, there's only an upside to caching $(this). You get miniscule but measurable runtime performance gains. More importantly, you can reduce the number of bytes that travel over the wire, and that directly translates to more dollars because faster page loads equal more sales.

When you look at it that way, you could actually say there's a quantifiable dollar cost to repeating $(this) and not caching it.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiongdoron is supporting MonicaView Question on Stackoverflow
Solution 1 - Javascriptgdoron is supporting MonicaView Answer on Stackoverflow
Solution 2 - JavascriptSLaksView Answer on Stackoverflow
Solution 3 - Javascriptcliffs of insanityView Answer on Stackoverflow
Solution 4 - Javascriptjosh3736View Answer on Stackoverflow