I’ve just finished reading JavaScript Patterns by Stoyan Stefanov and boy has it opened up my mind and inspired me to write better, faster, cleaner and more modular JavaScript code using the Module Pattern.
Stoyan’s book covers many patterns and anti-patterns (the common old approach to JavaScript coding).
Stoyan provides detailed explanations why and where to use each pattern inc. module pattern. Since there is so much content in this book I decided to write about what I believe will add immediate value to any developer working with JavaScript, how to make JavaScript better using the module pattern. |
No hacks around poor JavaScript
JavaScript is unlike back-end server-side code where if the code becomes a bottleneck you just throw more boxes (hardware) at it to speed thinks up. JavaScript downloads & runs within the user’s browser. So if you got lazy or just didn’t know better to follow Convention over Configuration (CoC) or the rapid development principle of Don’t Repeat Yourself (DRY) and you hacked something together.. the user will get poor experience and even limited to a single browser. This is where JavaScript Patterns play an important role and understanding them is the 1st step in becoming a JS Ninja.
JavaScript – what you need to know
Let’s shake some old grounds and cover the what you need to know about JavaScript in 2011.
- There are no classes in JavaScript. You create a blank object when you need one and then start adding members to it.
- Sometimes when people say “Singleton” in a JavaScript context, they mean the Module Pattern – covered below and discussed in detail in Stefanov’s Chapter 5. Every time you create an object using the object literal, you’re actually creating a Singleton. And there’s no special syntax involved.
- When you think about objects in JavaScript, simply think about hash tables of key – value pairs. Similar to what are called associative arrays in other languages.
- Use literal notation patterns instead of object definitions. Literal is more concise, expressive and less error-prone. See Appendix 1.1 at the end of this post for examples.
Module Pattern – organize your code
Let’s start with what’s most common out there on the internet. You may have seen (or even do) this.
Code sample – anti pattern
Declaring:
var array_string = "[object Array]"; var ops = Object.prototype.toString; var MAX_NUM = 123; function inArray (haystack, needle) { for (var i = 0, max = haystack.length; i < max; i += 1) { if (haystack[i] === needle) return i; } isEnabled = false; return −1; } function isArray (a) { return ops.call(a) === array_string; }; var pageTitle = "New title";
Calling:
isArray(arr_user);
The problems here are:
- All these are global (variable and functions) are shared among all the code in your application living in the global namespace. High chance of naming collisions between your and other developer’s code (think maintenance).
- isEnabled above has no var declaration so automatically becomes chained to the global namespace outside the function.
- When something in your code is chained to the top of the prototype it takes longer time to be found then if it’s within a module. I will discuss the JavaScript Prototype in another post and show examples with performance differences.
- Some best practices are broken – see below what these best practices should be.
Module Pattern – the solution, organize your code
There are many great patterns described in JavaScript Patterns by Stoyan Stefanov but my preference today is to use the Module Pattern. The Module Pattern is widely used because it provides structure and helps organize your code into self-contained de-coupled pieces of code. If you look at the source of jQuery you will find a similar pattern being used.
The Module Pattern is a combination of several patterns described in Stoyan’s book.
They include:
- Namespaces (Stefanov’s pg.87)
- Immediate functions (Stefanov’s pg.73)
- Private and privileged members (Stefanov’s pg.92) and
- Declaring dependencies (Stefanov’s pg.90)
And here’s how the same sample of code above would look when the Module Pattern was followed.
Module Pattern code sample – the pattern
Declaring:
var MYCOMPANY = MYCOMPANY || {}; // note the use of namespacing - similar to jQuery. MYCOMPANY.Page = (function () { 'use strict'; // [ private properties ] // note the chaining of var declarations vs a var on each line var pageTitle = "blank", isEnabled = false, array_string = "[object Array]", ops = Object.prototype.toString, MAX_NUM = 123; // constants always are in capital case // end var // [ private methods ] // note the use of literal patterns vs constructor functions function inArray(haystack, needle) { var i = 0, max = 0; for (max = haystack.length; i < max; i += 1) { if (haystack[i] === needle) { return i; } } return -1; } function isArray(a) { return ops.call(a) === array_string; // end var } // [ public methods ] return { init: function (title, enabled) { pageTitle = title; isEnabled = enabled; }, isArray: isArray, indexOf: inArray }; }());
Calling:
MYCOMPANY.Page.init('Page title', true); MYCOMPANY.Page.isArray(arr_user);
Code is now modularized and less prone to collisions.
JSLint: The JavaScript Code Quality Tool
Once you have written your new modularized code it’s a best practice to run it past JSLint. JSLint is a free JavaScript program that looks for problems & violations of some of the patterns in your JavaScript code. It is a code quality tool. Check it out here: http://www.jslint.com/
JavaScript best practices
- Curly brackets should always be used even if there is 1 expression. Code is then more readable and maintainable.
- Use 4 space indentation – also JSLint default. This way no matter what editor engineers use it is always displayed in the same manner.
- Like curly brackets, always use semicolons, even when they are implied by the JavaScript parser. Why slow down the compiler to clean up the mess during runtime.
- Naming convention for constructors is typically UpperCamelCase, functions lowerCamelCase, variables lowercase_separated_by_underscore and constants UPPER_CASE.
- Use whitespace as much as possible by separating all operators and their operands with spaces.
- Use Google’s Closure Compiler to minify your code before production AFTER you have passed it via JSLint (above).
Appendix
1.1 Constructors and their corresponding and preferred literal patterns.
Built-in constructors (avoid) | Literals and primitives (prefer) |
var o = new Object(); | var o = {}; |
var a = new Array(); | var a = []; |
var re = new RegExp( “[a-z]”,”g”); | var re = /[a-z]/g; |
var s = new String(); | var s = “”; |
var n = new Number(); | var n = 0; |
var b = new Boolean(); | var b = false; |
throw new Error(“uh-oh”); | throw { name: “Error”, message: “uh-oh” };… or throw Error(“uh-oh”); |
And that is it for now. Have I missed something or gotten something wrong above? If so please let me know and I will correct it. How is your JavaScript looking? Need help to get it fixed? Post below or contact me.
~ Ernest