[Coding] JavaScript Patterns (Ch. 2)

Posted by Khatharsis on June 12, 2013

A friend let me borrow JavaScript Patterns by Stoyan Stefanov earlier in the year, but I didn’t get around to it until now. JavaScript has been intimidating, even during it’s early years when it was often used for pop-ups, but I keep returning to try to master it. I guess the intricacies and slightly different logic from classic languages like Java or C# makes me motivated to better understand the language. I’ve already read through the book once as a quick read, but wanted to go through it again and take my time to absorb the different patterns and better practices as I keep working on my personal projects while searching for a job.

I’ve already been aware of minimizing global variables from Crockford’s JavaScript: The Good Parts book, but I wasn’t aware that the window object stores global variables as properties. For example:

aGlobalVar = "foo";
console.log(window["aGlobalVar"]); // "foo"
console.log(window.aGlobalVar); // "foo"

Declaring a variable without the use of the keyword var creates an implied global, whether declared outside of any function or inside of a function. Declaring a variable with the use of var is an explicit global. They function the same, but the real difference is the implied global is not really a variable, but a property of the global object (window). This means if the operator delete is used, the implied global will be deleted but the explicit global will not–properties can be deleted, but variables cannot.

Takeaway from this section: “the most important pattern for having fewer globals is to always use var to declare variables.” A good practice is to use a single var at the top of the function. In my latest few projects, I have tried to adopt this practice, but I also find myself wanting to separate related variables into blocks. While I declare my variables at the top of the function, I will break them into sections with var serving as a visual separator. This is probably not a good practice, but since I’m not used to the single var and find it a little confusing when quickly glancing over code (especially if I have a long list of variables), I find it helps. I think of it as a stepping stone towards the best practice of using a single var.

A related point is to avoid chaining “assignments as part of a var declaration” like:

function () {
    var a = b = "foo";
}

The right-to-left evaluation makes b a global variable, which is usually unintended.

Hoisting is an interesting aspect of JavaScript in that variables can be declared anywhere within a function, but they will get pulled up to the top of the function – hence why it’s better to declare variables at the top of the function because it will be done anyway. The following is an example from the book, which I found interesting and is a good example of the strange logic present in JavaScript:

myname = "global";
function func() {
    alert(myname); // "undefined"
    var myname="local";
    alert(myname); // "local"
}

What’s happening is really the same as if the code were written like the following:

myname = "global";
function func() {
    var myname;
    alert(myname); // "undefined"
    myname="local";
    alert(myname); // "local"
}



For loops are taught in a standard way and look something like:
for (var i = 0; i < anArray.length; i++){}.
With JavaScript being loosely typed, HtmlCollections can easily be mistaken as an array. One pattern to optimize for HtmlCollections is to save the length value in another variable so the new code will look like:
for (var i = 0, max = anArray.length; i < max, i++){}.
The above pattern can be combined with the single var pattern, essentially pulling out the var declarations outside of the loop:

var i,
    max;
for (i = 0, max = anArray.length; i < max, i++) {}


A caution with this combined pattern is to take care when moving the loop around other parts of the code as i and max can become global variables if they are not declared with var.

Micro-optimizations involve counting down rather than up and in most cases is not necessary.
--
For loops should be used with arrays and for-in loops with objects. For-in disregards the order of elements (in an array) or properties (in an object).

For-in loops should also be used with hasOwnProperty() to filter out prototype properties. This filter ensures properties specific to the object being enumerated over appears and not ancestor properties that it has inherited through prototype. An example looks like the following:

for (var i in myObject) {
    if (myObject.hasOwnProperty(i)) {
        console.log(myObject[i]);
    }
}


--
Switch statements should have a break for each case unless there is a good reason for falling through. If so, commenting that it is intended behavior will help someone else down the line. Switch statements should also have a default case to handle the event that none of the cases match.

Use === and !== when comparing variables. These comparison functions check both the values and the types of the variables, ensuring they are "true" comparisons rather than an implied typecasted comparisons. This is one issue I have problems with remembering because this syntax is not present in classical languages because they are strongly typed and unnecessary.

Avoid using eval() by remembering the mantra, "eval() is evil." There are security implications with using eval(). Passing strings to setInterval(), setTimeOut(), Function() is just like using eval() and should also be avoided. Implied globals can be made using eval(), providing another reason to avoid using it. However, if eval() must be used, consider using new Function() instead.

When using parseInt(), always include the radix as the second parameter, e.g., parseInt('08', 10).
--
The rest of the chapter dealt with coding conventions such as naming conventions and formatting so I won't include them in my notes. A lot of the content from this chapter was also present in Crockford's book and so it read more as a review for me. However, one tool I should start using more is JSLint.