This is an ongoing set of notes based on my learning of JavaScript patterns and best practices. It’s a collection of knowledge from various sources.
In addition code examples are being maintained as an executable set of specifications in the patterns.js repo on GitHub.
Objects
Objects are mutable keyed collections that contain properties. A
property can be any JavaScript value except for undefined
.
Object Literal Notation is ideal for on-demand object creation. You can start with a blank object and add functionality as you need.
1 2 3 4 5 6 7 |
|
But you can also create the same object at once:
1 2 3 4 5 6 |
|
I like this quote from the JavaScript Patterns book
Another reason why the literal is the preferred pattern for object creation is that it emphasizes that objects are simply mutable hashes and not something that needs to be baked from a “recipe” (from a class).
Prototype
JavaScript objects are all linked to a prototype object where it can
inherit properties. This is important for code-reuse patterns discussed
later. Object literals are linked to the Object.prototype
by default.
Functions
- Functions are first class objects. They can be passed around as values or augmented with properties and methods
- Provide local scope. Declarations of local variables get hoisted to the top of local scope.
Syntax for creating functions
Named function expressions
1 2 3 |
|
Anonymous functions. Same as above but without a name:
1 2 3 |
|
Function Declarations:
1 2 3 |
|
Invocation
When a function is invoked it’s passed the declared parameters and two additional ones:
- a reference to
this
- a reference to
arguments
The reference to this
depends on how the function was invoked.
Method Invocation
When a function is a property of an object, it is refered to as a
method. When a method is invoked this
refers to the containing object.
1 2 3 4 5 6 7 8 |
|
Function Invocation
When a function is not a property of an object, the function’s reference
to this
is bound to the global object.
1 2 3 |
|
Constructor Invocation
When an object is created with the new
keyword it’s refered to as a
Constructor. The object’s reference to this
is bound to that object.
1 2 3 4 5 6 |
|
When new
is not used this
inside the constructor will refer to the global object instead of the object itself. So a helpful pattern is to enforce the use of new
with a self-invoking contructor
1 2 3 4 5 6 7 8 9 |
|
Scope
Scope is determined by functions, not by blocks in JavaScript. Parameters and variables defined in a function are not visible outside of that function. Also, variables declared inside a function are visible anywhere within it – One interesting case is when an inner function has a longer lifetime than its outer function.
Immediate Functions
A pattern that wraps a function and immediately executes it. It helps avoid poluting the global namespace and also creates a closure, protecting private variables.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Code-Reuse and Inheritance
Reusing code is an important topic to any discussion of software development. In classical languages this is usually done with inheritance. JavaScript supports many different ways in which code can be reused. I like this quote from JavaScript: The Good Parts when thinking about how JavaScript differs from other languages:
In classical languages, objects are instances of classes, and a class can inherit from another class. JavaScript is a prototypal language, which means that objects inherit directly from other objects
The most natural inheritance pattern is to embrace the prototypal behavior and focus on objects inheriting properties of other objects.
Prototypal inheritance is easy with the Object.create
method in
ECMAScript 5:
1 2 3 4 5 |
|
This method is easy to pollyfil in environments that don’t support it natively:
1 2 3 4 5 6 7 8 9 10 |
|
Another approach to code-reuse to the apply psuedoclassical patterns of inheritance to JavaScript. The most straight forward and versitile way is called the Proxy Constructor Pattern. The idea is to have the child prototype point at a proxy object that in turn is linked to the parent via it’s prototype.
1 2 3 4 5 6 7 8 9 10 11 |
|
It is possible to make this pattern a little easier to use by wrapping it in some syntactical sugar, in a pattern called Klass
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
It can then be used like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Another pattern in code-reuse is the concept of borrowing methods. In cases where it doesn’t make sense to inherit all of the properties you can just borrow the ones you need:
1
|
|
Global Variables
It’s a good idea to minimize the number of global variables in a JavaScript application. The main reason is because of naming collisions between code bases. If two seperate code bases declare global variables with the same name unintended consequences are often a result.
Two main features of javascript as a language make the issue easier to create:
- Not having to declare variables before using them
- Implied globals – any variable you don’t declare becomes a property
of the global object
- ES5 strict mode will throw an error if assignments are made to implied globals
The easiest way to avoid global variables is to always declare variables
with the var
keyword.