I hope you’ve been enjoying the first three installments of 5 Things Everyone Could Learn from the jQuery Source. Here is the fourth installment.
Caching variables is a perfect example of one of the most common (but yet poorly-implemented) practices that JavaScript/jQuery developers do. Caching is making a copy of a variable that you are going to be referring to multiple times later in your code. This is usually done to improve efficiency. Here is an example of code that could benefit from caching:
if (document.getElementById("mainbody")) { doSomeStuffIfItIsMain(1); } doSomeStuffYouAlwaysDo(); if (document.getElementById("mainbody")) { doSomeStuffIfItIsMain(2); }
So, in this example, you start off by checking to see if there is a DOM element with the id of “mainbody” in the document. If there is, do the first set of stuff you would only do if there was a DOM element with the id of “mainbody”. Then, do the stuff you do regardless of “mainbody”‘s existence. Then, check for that same DOM element being present in the document, and if it is there, do the second set of stuff that only happens when “mainbody” is present. Will this work? Absolutely! Is it the best way to do this? Not really! Here is that same code, using a cached variable:
var mainbody = document.getElementById("mainbody"); if (typeof mainbody === "object") { //See what we did there? We're using the concepts we JUST talked about! doSomeStuffIfItIsMain(1); } doSomeStuffYouAlwaysDo(); if (mainbody) { doSomeStuffIfItIsMain(2); }
The benefit to this version is that you only have to evaluate the entire DOM of the page once, instead of twice to get the same element. And just imagine if there are four or five tests on your page for mainbody? You would be making your JavaScript analyze the whole DOM five times on every load! That is an example of performance problems with a lot of well-intentioned developers’ JavaScript. Whenever you have to analyze the entire DOM, this is called DOM Traversal. And it increases the time it takes your script to run. Why make your script do it more often than you need to? Traversing the DOM to find ten different elements one time each is a lot better than traversing the DOM to find one element, the same element, ten times. (Disclaimer: getElementById() is very fast, and is used by jQuery when it sees $(“#selector”))
Anytime you have a jQuery object (in this example, it would have been $(“#mainbody”)) that you are going to be doing multiple actions on (that you can’t chain for whatever reason), cache that object. This keeps you from making jQuery look up that DOM object each and every time you type $(“#mainbody”).
One of the most common practices is using the variable name ‘that’ to cache the value of JavaScript’s ‘this’ if you are going to be using it later. (For a good discussion on ‘this’, read the MDN article) The line numbers 5080-5089 in the jQuery 2.0 source show a more semantic approach to doing this type of caching:
if ( typeof selector !== "string" ) { self = this; return this.pushStack( jQuery( selector ).filter(function() { for ( i = 0; i < l; i++ ) { if ( jQuery.contains( self[ i ], this ) ) { return true; } } }) ); }
On the second line, the ‘this’ primitive is stored in the variable ‘self’. This variable is local to the containing function. Because we need to iterate through the elements of the original ‘this’ for the purpose of testing using jQuery.contains(), we cache it in ‘self’ and then do our comparison.
The reason using ‘self’ here is better than using ‘that’ is because in this context, in the code, ‘self’ refers to an the original element(s) being tested on the page. So reading this, I know because of the semantics of the variable what is stored in ‘self’. Using a semantic name like this is far more maintainable and understandable than naming all cached versions of ‘this’ as ‘that’. Just because it’s grammatically ironic to use ‘that’ doesn’t make it a better method than semantic variable naming. It won’t make other people reading your code like you any more. I promise. What will earn you kudos and respect is having someone else read your code and be able to easily understand what it does, instead of chasing down vague nomenclature and trying to understand what ‘this’ or ‘that’ is doing.
The benefit to this version is that you only have to evaluate the entire DOM of the page once, instead of twice to get the same element. And just imagine if there are four or five tests on your page for mainbody? You would be making your JavaScript analyze the whole DOM five times on every load! That is an example of performance problems with a lot of well-intentioned developers’ JavaScript. Whenever you have to analyze the entire DOM, this is called DOM Traversal. And it increases the time it takes your script to run. Why make your script do it more often than you need to? Traversing the DOM to find ten different elements one time each is a lot better than traversing the DOM to find one element, the same element, ten times. (Disclaimer: getElementById() is very fast, and is used by jQuery when it sees $(“#selector”))