# JavaScript Patterns
## Chapter 2: Essentials
### Writing Maintanable Code
Why do we need to write code in maitanable way?
* Time to relearn and understand the problem
* Time to understand the code that is supposed to solve the problem
What is maintainable code?
* Is readable
* Is consistent
* Is predictable
* Looks as if it was written by the same person
* Is documented
### Minimizing Global
**Local variable:** a variable declared inside of a function
**Global variable:** those declared outside of any function or simply used without being declared.
``` javascript
myglobal = "hello"; // antipattern
console.log(myglobal); // "hello"
console.log(window.myglobal); // "hello"
console.log(window["myglobal"]); // "hello"
console.log(this.myglobal); // "hello"
```
### The Problem with Globals
Global variables are shared in a JavaScript application or web page and there is always a chance of naming collisions.
* A third-party JavaScript library
* Scripts from an advertising partner
* Code from a third-party user tracking and analytics script
* Different kinds of widgets, badges, and buttons
**Implied globals:** any variable you don’t declare becomes a property of the global object
**Antipattern:**
``` javascript
function sum(x, y) {
result = x + y;
return result;
}
```
``` javascript
function foo() {
var a = b = 0;
// ...
}
```
**Coding pattern:**
``` javascript
function sum(x, y) {
var result = x + y;
return result;
}
```
``` javascript
function foo() {
var a, b;
// ...
a = b = 0; // both local
}
```
### Side Effects When Forgetting *var*
difference between implied globals and explicitly defined ones
* Globals created with ***var*** cannot be deleted.
* Implied globals created without ***var*** can be deleted.
``` javascript
// define three globals
var global_var = 1;
global_novar = 2; // antipattern
(function () {
global_fromfunc = 3; // antipattern
}());
// attempt to delete
delete global_var; // false
delete global_novar; // true
delete global_fromfunc; // true
// test the deletion
typeof global_var; // "number"
typeof global_novar; // "undefined"
typeof global_fromfunc; // "undefined"
```
In ES5 strict mode, assignments to undeclared variables (such as the two antipatterns in the preceding snippet) will throw an error.
### Access to the Global Object
In the browsers, the global object is accessible from any part of the code via the window property. In other environment, you can access global objects via ***this*** instead of ***window***.
``` javascript
// In web browsers, the window object is also the global object:
console.log(this === window); // true
a = 37;
console.log(window.a); // 37
this.b = "MDN";
console.log(window.b) // "MDN"
console.log(b) // "MDN"
```
### Single *var* Pattern
Benefits of using single var:
* Provides a single place to look for all the local variables needed by the function
* Prevents logical errors when a variable is used before it’s defined
* Helps you remember to declare variables and therefore minimize globals
* Is less code
``` javascript
function func() {
var a = 1,
b = 2,
sum = a + b,
myobject = {},
i,
j;
// function body...
}
```
### Hoisting: A Problem with Scattered vars
JavaScript enables you to have multiple var statements anywhere in a function, and they all act as if the variables were declared at the top of the function.
**Antipattern:**
``` javascript
myname = "global"; // global variable
function func() {
alert(myname); // "undefined"
var myname = "local";
alert(myname); // "local"
}
func();
```
### for Loops
In for loops you iterate over arrays or array-like objects such as **arguments** and **HTMLCollection** objects.
**HTMLCollections** are objects returned by DOM methods such as:
* document.getElementsByName()
* document.getElementsByClassName()
* document.getElementsByTagName()
``` javascript
// sub-optimal loop
for (var i = 0; i < myarray.length; i++) {
// do something with myarray[i]
}
```
You can also take the ***var*** out of the loop.
Benefit: stick to the single ***var*** pattern.
Drawback: a little harder to copy and paste whole loops.
``` javascript
function looper() {
var i = 0,
max,
myarray = [];
// ...
for (i = 0, max = myarray.length; i < max; i++) {
// do something with myarray[i]
}
}
```
Two variations of the for pattern introduce some micro-optimizations because they:
* Use one less variable (no max)
* Count down to 0, which is usually faster because it’s more efficient to compare to 0 than to the length of the array or to anything other than 0
``` javascript
var i, myarray = [];
for (i = myarray.length; i--;) {
// do something with myarray[i]
}
```
``` javascript
var myarray = [],
i = myarray.length;
while (i--) {
// do something with myarray[i]
}
```
### for-in Loops
**for-in** loops should be used to iterate over nonarray objects. Looping with for-in is also called enumeration.
It’s important to use the method hasOwnProperty() when iterating over object properties to filter out properties that come down the prototype chain.
``` javascript
// the object
var man = {
hands: 2,
legs: 2,
heads: 1
};
// somewhere else in the code
// a method was added to all objects
if (typeof Object.prototype.clone === "undefined") {
Object.prototype.clone = function () {};
}
```
**Coding pattern:**
```javascript
// for-in loop
for (var i in man) {
if (man.hasOwnProperty(i)) { // filter
console.log(i, ":", man[i]);
}
}
/*
result in the console
hands : 2
legs : 2
heads : 1
*/
```
**Antipattern:**
``` javascript
// for-in loop without checking hasOwnProperty()
for (var i in man) {
console.log(i, ":", man[i]);
}
/*
result in the console
hands : 2
legs : 2
heads : 1
clone: function()
*/
```
### (Not) Augmenting Built-in Prototypes
Other developers using your code will probably expect thebuilt-in JavaScript methods to work consistently and will not expect your additions.
Therefore it’s best if you don’t augment built-in prototypes. You can make an exception
of the rule only when all these conditions are met:
1. It’s expected that future ECMAScript versions or JavaScript implementations will implement this functionality as a built-in method consistently. For example, you can add methods described in ECMAScript 5 while waiting for the browsers to catch up. In this case you’re just defining the useful methods ahead of time.
2. You check if your custom property or method doesn’t exist already—maybe already implemented somewhere else in the code or already part of the JavaScript engine of one of the browsers you support.
3. You clearly document and communicate the change with the team.
### switch Pattern
You can improve the readability and robustness of your ***switch*** statements by following this pattern:
``` javascript
var inspect_me = 0,
result = '';
switch (inspect_me) {
case 0:
result = "zero";
break;
case 1:
result = "one";
break;
default:
result = "unknown";
}
```
### Avoiding Implied Typecasting
To avoid confusion caused by the implied typecasting, always use the === and !== operators that check both the values and the type of the expressions you compare:
**Coding pattern:**
``` javascript
var zero = 0;
if (zero === false) {
// not executing because zero is 0, not false
}
```
**Antipattern:**
``` javascript
if (zero == false) {
// this block is executed...
}
```
### Avoiding eval()
This function takes an arbitrary string and executes it as JavaScript code.
**Coding pattern:**
``` javascript
var property = "name";
console.log(obj[property]);
```
**Antipattern:**
``` javascript
var property = "name";
console.log(eval("obj." + property));
```
Using the new Function() constructor is similar to eval() and should be approached with care. Another way to prevent automatic globals is to wrap the eval() call into an immediate function.
``` javascript
console.log(typeof un); // "undefined"
console.log(typeof deux); // "undefined"
console.log(typeof trois); // "undefined"
var jsstring = "var un = 1; console.log(un);";
eval(jsstring); // logs "1"
jsstring = "var deux = 2; console.log(deux);";
new Function(jsstring)(); // logs "2"
jsstring = "var trois = 3; console.log(trois);";
(function () {
eval(jsstring);
}()); // logs "3"
console.log(typeof un); // "number"
console.log(typeof deux); // "undefined"
console.log(typeof trois); // "undefined"
```
**Function** constructor can do less local variable pollution. In the following example, eval() can access and modify a variable in its outer
scope, whereas **Function** cannot.
``` javascript
(function () {
var local = 1;
eval("local = 3; console.log(local)"); // logs 3
console.log(local); // logs 3
}());
(function () {
var local = 1;
Function("console.log(typeof local);")(); // logs undefined
}());
```
### Number Conversions with parseInt()
Using parseInt() you can get a numeric value from a string. The function accepts a second radix parameter, which is often omitted but shouldn’t be.
``` javascript
var month = "06",
year = "09";
month = parseInt(month, 10);
year = parseInt(year, 10);
```
### Coding Conventions
It’s important to establish and follow coding conventions—they make your code consistent, predictable, and much easier to read and understand. A new developer joining the team can read through the conventions and be productive much sooner, understanding the code written by any other team member.
It’s much more important to establish and consistently follow a convention, any convention, than what the exact details of that convention will be.
### Indentation
Code without indentation is impossible to read. The only thing worse is code with inconsistent indentation, because it looks like it’s following a convention, but it may have confusing surprises along the way.
## Chapter 3: Literals and Constructors
### Object Literal
Objects in JavaScript is like key-value pairs:
* The values can be primitives or other objects; in both cases they are called properties.
* The values can also be functions, in which case they are called methods.
**Object literal notation:**
``` javascript
// start with an empty object
var dog = {};
// add one property
dog.name = "Benji";
// now add a method
dog.getName = function () {
return dog.name;
};
```
At any time in the life of the program you can:
* Change the values of properties and methods
``` javascript
dog.getName = function () {
// redefine the method to return
// a hardcoded value
return "Fido";
};
```
* Remove properties/methods completely
``` javascript
delete dog.name;
```
* Add more properties and methods
``` javascript
dog.say = function () {
return "Woof!";
};
dog.fleas = true;
```
Not required to start with an empty object:
``` javascript
var dog = {
name: "Benji",
getName: function () {
return this.name;
}
};
```
### The Object Literal Syntax
* Wrap the object in curly braces.
* Comma-delimit the properties and methods inside the object.
* Separate property names and property values with a colon.
* When you assign the object to a variable, don’t forget the semicolon after the closing.
### Objects from a Constructor
You can create objects using your own constructor functions or using some of the built-in constructors such as `Object()`, `Date()`, `String()` and so on.
``` javascript
// one way -- using a literal
var car = {goes: "far"};
// another way -- using a built-in constructor
// warning: this is an antipattern
var car = new Object();
car.goes = "far";
```
Reasons to use a literal rather than a constructor:
* The literal notation is that it’s shorter to type.
* objects are simply mutable hashes and not something that needs to be baked from a “recipe” (from a class).
### Object Constructor Catch
The behavior of the `Object()` constructor can lead to unexpected results when the value you pass to it is dynamic and not known until runtime.
``` javascript
// Warning: antipatterns ahead
// an empty object
var o = new Object();
console.log(o.constructor === Object); // true
// a number object
var o = new Object(1);
console.log(o.constructor === Number); // true
console.log(o.toFixed(2)); // "1.00"
// a string object
var o = new Object("I am a string");
console.log(o.constructor === String); // true
// normal objects don't have a substring()
// method but string objects do
console.log(typeof o.substring); // "function"
// a boolean object
var o = new Object(true);
console.log(o.constructor === Boolean); // true
```
### Custom Constructor Functions
Create objects using your own custom constructor functions:
``` javascript
var adam = new Person("Adam");
adam.say(); // "I am Adam"
var Person = function (name) {
this.name = name;
this.say = function () {
return "I am " + this.name;
};
};
```
When you invoke the constructor function with new, the following happens inside the function:
* An empty object is created and referenced by this variable, inheriting the prototype of the function.
* Properties and methods are added to the object referenced by **this**.
* The newly created object referenced by this is returned at the end implicitly (if no other object was returned explicitly).
``` javascript
var Person = function (name) {
// create a new object
// using the object literal
// var this = {};
// add properties and methods
this.name = name;
this.say = function () {
return "I am " + this.name;
};
// return this;
};
```
### Constructor’s Return Values
When invoked with new, a constructor function always returns an object; by default it’s the object referred to by this. If you don’t add any properties to this inside of your constructor, an “empty” object is returned.
Constructors implicitly return this, even when you don’t have a return statement in the function. But you can return any other object of your choosing. In the next example, a new object referenced by that is created and returned.
``` javascript
var Objectmaker = function () {
// this `name` property will be ignored
// because the constructor
// decides to return another object instead
this.name = "This is it";
// creating and returning a new object
var that = {};
that.name = "And that's that";
return that;
};
// test
var o = new Objectmaker();
console.log(o.name); // "And that's that"
```
### Patterns for Enforcing new
What happens if you forget new when you invoke a constructor?
This is not going to cause syntax or runtime errors but might lead to logical errors. That’s because when you forget **new**, this inside the constructor will point to the global object.
``` javascript
// constructor
function Waffle() {
this.tastes = "yummy";
}
// a new object
var good_morning = new Waffle();
console.log(typeof good_morning); // "object"
console.log(good_morning.tastes); // "yummy"
// antipattern:
// forgotten `new`
var good_morning = Waffle();
console.log(typeof good_morning); // "undefined"
console.log(window.tastes); // "yummy"
```
### Naming Convention
Uppercase the first letter in constructor names (MyConstructor) and lowercase it in “normal” functions and methods (myFunction).
### Using that
Instead of adding all members to this, you add them to that and then return that.
``` javascript
function Waffle() {
var that = {};
that.tastes = "yummy";
return that;
}
```
Or just return an object from a literal like so.
``` javascript
function Waffle() {
return {
tastes: "yummy"
};
}
```
Using any of the implementations above Waffle() always returns an object, regardless of how it’s called.
``` javascript
var first = new Waffle(),
second = Waffle();
console.log(first.tastes); // "yummy"
console.log(second.tastes); // "yummy"
```
The problem with this pattern is that the link to the prototype is lost, so any members you add to the Waffle() prototype will not be available to the objects.
## Chapter 4: Functions
There are two main features of the functions in JavaScript that make them special — the first is that functions are first-class **objects** and the second is that they provide **scope**.
Functions are objects that:
* Can be created dynamically at runtime, during the execution of the program
* Can be assigned to variables, can have their references copied to other variables, can be augmented, and, except for a few special cases, can be deleted
* Can be passed as arguments to other functions and can also be returned by other functions
* Can have their own properties and methods
``` javascript
// antipattern
// for demo purposes only
var add = new Function('a, b', 'return a + b');
add(1, 2); // returns 3
```
Using the **Function()** constructor is not a good idea though (it’s as bad as **eval()**) because code is passed around as a string and evaluated. It’s also inconvenient to write (and read) because you have to escape quotes.
The second important feature is that functions provide scope. In JavaScript there’s no curly braces local scope; in other words, blocks don’t create scope.
### Disambiguation of Terminology
**named function expression**
``` javascript
// named function expression
var add = function add(a, b) {
return a + b;
};
```
**unnamed function expression**, also known as simply as **function expression** or most commonly as an **anonymous function**
``` javascript
// function expression, a.k.a. anonymous function
var add = function (a, b) {
return a + b;
};
```
The only difference between both is that the name property of the function object will be a blank string.
**function declarations**
``` javascript
function foo() {
// function body goes here
}
```
The semicolon is not needed in function declarations but is required in function expressions.
### Declarations Versus Expressions: Names and Hoisting
``` javascript
// this is a function expression,
// pased as an argument to the function `callMe`
callMe(function () {
// I am an unnamed function expression
// also known as an anonymous function
});
// this is a named function expression
callMe(function me() {
// I am a named function expression
// and my name is "me"
});
// another function expression
var myobject = {
say: function () {
// I am a function expression
}
};
```
Function declarations can only appear in “program code,” meaning inside of the bodies of other functions or in the global space.
``` javascript
// global scope
function foo() {}
function local() {
// local scope
function bar() {}
return bar;
}
```
### Function’s name Property
In function declarations and named function expressions, the name property is defined. In anonymous function expressions, it depends on the implementation; it could be undefined (IE) or defined with an empty string (Firefox, WebKit):
``` javascript
function foo() {} // declaration
var bar = function () {}; // expression
var baz = function baz() {}; // named expression
foo.name; // "foo"
bar.name; // ""
baz.name; // "baz"
```
The name property is useful when debugging code in Firebug or other debuggers. When the debugger needs to show you an error in a function, it can check for the presence of the name property and use it as an indicator.
### Function Hoisting
As you know, all variables, no matter where in the function body they are declared, get hoisted to the top of the function behind the scenes. The same applies for functions because they are just objects assigned to variables.
``` javascript
// antipattern
// for illustration only
// global functions
function foo() {
console.log('global foo');
}
function bar() {
console.log('global bar');
}
function hoistMe() {
console.log(typeof foo); // "function"
console.log(typeof bar); // "undefined"
foo(); // "local foo"
bar(); // TypeError: bar is not a function
// function declaration:
// variable 'foo' and its implementation both get hoisted
function foo() {
console.log('local foo');
}
// function expression:
// only variable 'bar' gets hoisted
// not the implementation
var bar = function () {
console.log('local bar');
};
}
hoistMe();
```
### Callback Pattern
Functions are objects, which means that they can be passed as arguments to other
functions.
``` javascript
function writeCode(callback) {
// do something...
callback();
// ...
}
function introduceBugs() {
// ... make bugs
}
writeCode(introduceBugs);
```
### A Callback Example
The generic function could be called, for example, **findNodes()**, and its task would be to crawl the DOM tree of a page and return an array of page elements:
``` javascript
var findNodes = function () {
var i = 100000, // big, heavy loop
nodes = [], // stores the result
found; // the next node found
while (i) {
i -= 1;
// complex logic here...
nodes.push(found);
}
return nodes;
};
```
Another different function, for example a function called **hide()** which, as the
name suggests, hides the nodes from the page:
``` javascript
var hide = function (nodes) {
var i = 0, max = nodes.length;
for (; i < max; i += 1) {
nodes[i].style.display = "none";
}
};
// executing the functions
hide(findNodes());
```
This implementation is inefficient, because **hide()** has to loop again through the array of nodes returned by **findNodes()**. It would be more efficient if you could avoid this loop and hide the nodes as soon as you select them in **findNodes()**.
``` javascript
// refactored findNodes() to accept a callback
var findNodes = function (callback) {
var i = 100000,
nodes = [],
found;// check if callback is callable
if (typeof callback !== "function") {
callback = false;
}
while (i) {
i -= 1;
// complex logic here...
// now callback:
if (callback) {
callback(found);
}
nodes.push(found);
}
return nodes;
};
// a callback function
var hide = function (node) {
node.style.display = "none";
};
// find the nodes and hide them as you go
findNodes(hide);
// passing an anonymous callback
findNodes(function (node) {
node.style.display = "block";
});
```
### Immediate Functions
The immediate function pattern is a syntax that enables you to execute a function as soon as it is defined.
``` javascript
(function () {
alert('watch out!');
}());
```
This pattern is in essence just a function expression (either named or anonymous), which is executed right after its creation.
The pattern consists of the following parts:
* You define a function using a function expression. (A function declaration won’t work.)
* You add a set of parentheses at the end, which causes the function to be executed immediately.
* You wrap the whole function in parentheses (required only if you don’t assign the function to a variable).
alternative syntax:
``` javascript
(function () {
alert('watch out!');
})();
```
This pattern is useful because it provides a scope *sandbox*.
Reasons:
* This code needs to be done only once.
* The code requires some temporary variables.
``` javascript
(function () {
var days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
today = new Date(),
msg = 'Today is ' + days[today.getDay()] + ', ' + today.getDate();
alert(msg);
}()); // "Today is Fri, 13"
```
If this code weren’t wrapped in an immediate function, then the variables days, today, and msg would all be global variables, leftovers from the initialization code.
### Parameters of an Immediate Function
You can also pass arguments to immediate functions:
``` javascript
// prints:
// I met Joe Black on Fri Aug 13 2010 23:26:59 GMT-0800 (PST)
(function (who, when) {
console.log("I met " + who + " on " + when);
}("Joe Black", new Date()));
```
### Returned Values from Immediate Functions
Just like any other function, an immediate function can return values and these return values can be assigned to variables:
``` javascript
var result = (function () {
return 2 + 2;
}());
```
Another way to achieve the same is to omit the parentheses that wrap the function.
``` javascript
var result = function () {
return 2 + 2;
}();
```
This syntax is simpler, but it may look a bit misleading.
``` javascript
var result = (function () {
return 2 + 2;
})();
```
The previous examples returned a primitive integer value as the result of executing the immediate function. But instead of a primitive value, an immediate function can return any type of value, including another function.
``` javascript
var getResult = (function () {
var res = 2 + 2;
return function () {
return res;
};
}());
```
Immediate functions can also be used when you define object properties.
``` javascript
var o = {
message: (function () {
var who = "me",
what = "call";
return what + " " + who;
}()),
getMsg: function () {
return this.message;
}
};
// usage
o.getMsg(); // "call me"
o.message; // "call me"
```
### Benefits and Usage
The immediate function pattern is widely used. It helps you wrap an amount of work you want to do without leaving any global variables behind. All the variables you define will be local to the self-invoking functions and you don’t have to worry about polluting the global space with temporary variables.
### Immediate Object Initialization
Another way to protect from global scope pollution, similar to the immediate functions pattern previously described, is the following immediate object initialization pattern.
``` javascript
({
// here you can define setting values
// a.k.a. configuration constants
maxwidth: 600,
maxheight: 400,
// you can also define utility methods
gimmeMax: function () {
return this.maxwidth + "x" + this.maxheight;
},
// initialize
init: function () {
console.log(this.gimmeMax());
// more init tasks...
}
}).init();
```
The benefits of this pattern are the same as the immediate function pattern: you protect the global namespace while performing the one-off initialization tasks.
### Init-Time Branching
Init-time branching (also called load-time branching) is an optimization pattern. When you know that a certain condition will not change throughout the life of the program, it makes sense to test the condition only once.
``` javascript
// BEFORE
var utils = {
addListener: function (el, type, fn) {
if (typeof window.addEventListener === 'function') {
el.addEventListener(type, fn, false);
} else if (typeof document.attachEvent === 'function') { // IE
el.attachEvent('on' + type, fn);
} else { // older browsers
el['on' + type] = fn;
}
},
removeListener: function (el, type, fn) {
// pretty much the same...
}
};
```
The problem with this code is that it’s a bit inefficient. Every time you call **utils.addListener()** or **utils.removeListener()**, the same checks get executed over and over again.
``` javascript
// AFTER
// the interface
var utils = {
addListener: null,
removeListener: null
};
// the implementation
if (typeof window.addEventListener === 'function') {
utils.addListener = function (el, type, fn) {
el.addEventListener(type, fn, false);
};
utils.removeListener = function (el, type, fn) {
el.removeEventListener(type, fn, false);
};
} else if (typeof document.attachEvent === 'function') { // IE
utils.addListener = function (el, type, fn) {
el.attachEvent('on' + type, fn);
};
utils.removeListener = function (el, type, fn) {
el.detachEvent('on' + type, fn);
};
} else { // older browsers
utils.addListener = function (el, type, fn) {
el['on' + type] = fn;
};
utils.removeListener = function (el, type, fn) {
el['on' + type] = null;
};
}
```