user1032531
user1032531

Reputation: 26281

Should JavaScript local variables be intermittently used to improve performance?

Consider the following two sections of script. The first is one line shorter and uses one less variable $t, however, converts this into a jQuery object one additional time.

From a performance (not readability) perspective, is one better than the other?

If the first is better, is there a point where one would want to use the second such as I need to convert this into a jQuery object one hundred times? Are there any rules of thumb when this transition should be made?

$(".click").click(function(){
    $('body').data('link',$(this));
    $("#dialog").data('id',$('#id').val()).data('status',$(this).text()).dialog("open");
});

$(".click").click(function(){
    var $t=$(this);
    $('body').data('link',$t);
    $("#dialog").data('id',$('#id').val()).data('status',$t.text()).dialog("open");
});

Upvotes: 0

Views: 47

Answers (2)

Eddie
Eddie

Reputation: 1063

Obviously, the second example is more efficient from a performance perspective.

Imagine you are a builder and you are on a ladder fixing up a broken ceiling. Your first example is like you have the tools you need in you toolbox down on the floor. The second example is like you have tools right in your tool belt and you don't have to climb down the ladder to get the tools and climb up again.

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1074545

It's probably faster, as $() does a bit of work to figure out what you've given it. It's extremely unlikely to matter, when you're giving $() a DOM element. If you're not in a tight loop, it's not important. Handling a click isn't exactly a performance-critical bit of code.

Where you get into differences is when you're repeatedly querying the DOM, e.g.:

$(".foo[data-nifty]").doThis();
$(".foo[data-nifty]").doThat();
$(".foo[data-nifty]").doTheOther();

There, you're forcing repeated searches of the DOM for all elements with class foo and a data-nifty attribute for no good reason. Now, unless that's in a loop, it probably doesn't matter either, but that's the kind of place you should be looking out for. If all three of the methods are chainable, write a chain, or use a temporary variable.

In general, write readable code, test early and often, and when you see real-world performance issues, deal with them.

The converse is also something to look for:

$(".foo").click(function() {
    var $t = $(this);
    $t.doThis();
    $t.doThat();
    $t.find(".something").not(".hooked").addClass("hooked").on("click", function() {
        // Do something here without using `$t`...
    });
});

There, we're looking within the clicked .foo element for any .something that doesn't have .hooked and, if found, adding a click handler to it. (This is obviously quite contrived; we'd use event delegation instead. But assume it's something that we would really write.)

In theory, if there were any new .somethings hooked, then their event handler is retained, and since it's a closure over the context of that click, the $t variable is kept in memory, meaning that whatever the $t variable refers to is also kept in memory. And so we could end up using more memory than we would ideally want to. (Since the set of DOM elements in $t isn't something we need to keep in $t.)

In practice, modern engines can and sometimes do "optimize" closures, releasing variables that theory says they need to keep, if they can prove to themselves they can do it without causing side-effects. But relying on that when you don't need to is not ideal. In the above, you could add $t = undefined; or $t = null; at the end to release the jQuery set it refers to. The context of the call and the $t variable may still be kept (barring JavaScript engine optimizations), but at least the jQuery set $t used to refer to isn't.

Upvotes: 3

Related Questions