JavaScript is the language of the Web. It started as a way to manipulate a few selected types of elements in a web page (such as images and form fields), but it has grown tremendously. In addition to client-side browser scripting, these days you can use JavaScript to program for an increasing variety of platforms. You can write server-side code (using .NET or Node.js), desktop applications (that work on all operating systems) and application extensions (e.g., for Firefox or Photoshop), mobile applications, and command-line scripts.
JavaScript is also an unusual language. It doesnât have classes, and functions are first-class objects used for many tasks. Initially the language was considered deficient by many developers, but in more recent years these sentiments have changed. Interestingly, languages such as Java and PHP started adding features such as closures and anonymous functions, which JavaScript developers have been enjoying and taking for granted for a while.
JavaScript is dynamic enough that you can make it look and feel like another language youâre already comfortable with. But the better approach is to embrace its differences and study its specific patterns.
A pattern in the broader sense of the word is a âtheme of recurring events or objectsâ¦it can be a template or model which can be used to generate thingsâ (http://en.wikipedia.org/wiki/Pattern).
In software development, a pattern is a solution to a common problem. A pattern is not necessarily a code solution ready for copy-and-paste but more of a best practice, a useful abstraction, and a template for solving categories of problems.
It is important to identify patterns because:
They help us write better code using proven practices and not reinvent the wheel.
They provide a level of abstractionâthe brain can hold only so much at a given time, so when you think about a more complex problem, it helps if you donât bother with the low-level details but account for them with self-contained building blocks (patterns).
They improve communication between developers and teams, which are often in remote locations and donât communicate face to face. Simply putting a label on some coding technique or approach makes it easier to make sure weâre talking about the same thing. For example, itâs easier to say (and think) âimmediate function,â than âthis thing where you wrap the function in parentheses and at the end of it put another set of parentheses to invoke the function right where youâve defined it.â
This book discusses the following types of patterns:
Design patterns
Coding patterns
Antipatterns
Design patterns are those initially defined by the âGang of Fourâ book (named so after its four authors), originally published in distant 1994 under the title Design Patterns: Elements of Reusable Object-Oriented Software. Examples of design patterns are singleton, factory, decorator, observer, and so on. The thing about design patterns in relation to JavaScript is that, although language-independent, the design patterns were mostly studied from the perspective of strongly typed languages, such as C++ and Java. Sometimes it doesnât necessarily make sense to apply them verbatim in a loosely typed dynamic language such as JavaScript. Sometimes these patterns are workarounds that deal with the strongly typed nature of the languages and the class-based inheritance. In JavaScript there might be simpler alternatives. This book discusses JavaScript implementations of several design patterns in Chapter 7.
The coding patterns are much more interesting; they are JavaScript-specific patterns and good practices related to the unique features of the language, such as the various uses of functions. JavaScript coding patterns are the main topic of the book.
You might come across an occasional antipattern in the book. Antipatterns have a bit of negative or even insulting sound to their name, but that neednât be the case. An antipattern is not the same as a bug or a coding error; itâs just a common approach that causes more problems than it solves. Antipatterns are clearly marked with a comment in the code.
Letâs quickly go over a few important concepts that provide a context for the following chapters.
JavaScript is an object-oriented language, which often surprises
developers who have previously looked at the language and dismissed
it. Anything you look at in a piece of JavaScript code has a good
chance of being an object. Only five primitive types are not objects:
number, string, boolean, null
, and
undefined
, and the first three have
corresponding object representation in the form of primitive wrappers
(discussed in the next chapter). Number, string, and boolean primitive
values are easily converted to objects either by the programmer or
sometimes behind the scenes by the JavaScript interpreter.
Functions are objects, too. They can have properties and methods.
The simplest thing you do in any language is define a variable. Well, in JavaScript when you define a
variable, youâre already dealing with objects. First, the variable
automatically becomes a property of an internal object
known as an Activation Object (or a property of the global object if itâs a global
variable). Second, this variable is actually also object-like because
it has its own properties (called attributes), which
determine whether the variable can be changed, deleted, or enumerated
in a for-in
loop. These attributes
are not directly exposed in ECMAScript 3, but edition 5 offers special
descriptor methods for manipulating them.
So what are the objects? Because they do so many things they must be quite special. Actually they are extremely simple. An object is just a collection of named properties, a list of key-value pairs (almost identical to an associative array in other languages). Some of the properties could be functions (function objects), in which case we call them methods.
Another thing about the objects you create is that you can modify them at any time. (Although ECMAScript 5 introduces APIs to prevent mutations.) You can take an object and add, remove, and update its members. If youâre concerned about privacy and access, weâll see patterns for this as well.
And one last thing to keep in mind is that there are two main types of objects:
The native objects can further be categorized as
built-in (for example, Array
, Date
) or user-defined
(var o = {};
).
Host objects are, for example, window
and all the DOM objects. If youâre wondering whether youâre using host
objects, try running your code in a different, nonbrowser environment.
If it works fine, youâre probably using only native objects.
Youâll see this statement repeated on several occasions throughout the book: There are no classes in JavaScript. This is a novel concept to seasoned programmers in other languages and it takes more than a few repetitions and more than a little effort to âunlearnâ classes and accept that JavaScript deals only with objects.
Not having classes makes your programs shorterâyou donât need to have a class to create an object. Consider this Java-like object creation:
// Java object creation HelloOO hello_oo = new HelloOO();
Repeating the same thing three times looks like an overhead when it comes to creating simple objects. And more often than not, we want to keep our objects simple.
In JavaScript you create a blank object when you need one and then start adding interesting members to it. You compose objects by adding primitives, functions, or other objects to them as their properties. A âblankâ object is not entirely blank; it comes with a few built-in properties already but has no âownâ properties. We talk about this more in the next chapter.
One of the general rules in the Gang of Four book says, âPrefer object composition to class inheritance.â This means that if you can create objects out of available pieces you have lying around, this is a much better approach than creating long parent-child inheritance chains and classifications. In JavaScript itâs easy to follow this adviceâsimply because there are no classes and object composition is what you do anyway.
JavaScript does have inheritance, although this is just one way to reuse
code. (And thereâs an entire chapter on code reuse.) Inheritance can
be accomplished in various ways, which usually make use of prototypes.
A prototype is an object (no
surprises) and every function you create automatically gets
a prototype
property
that points to a new blank object. This object is almost identical to
an object created with an object literal or Object()
constructor, except that
its constructor
property
points to the function you create and not to the built-in Object()
. You can add members to this blank
object and later have other objects inherit from this object and use
its properties as their own.
Weâll discuss inheritance in detail, but for now just keep in
mind that the prototype is an object (not a class or anything special)
and every function has a prototype
property.
JavaScript programs need an environment to run. The natural habitat for a JavaScript program is the browser, but thatâs not the only environment. The patterns in the book are mostly related to the core JavaScript (ECMAScript) so they are environment-agnostic. Exceptions are:
Chapter 8, which specifically deals with browser patterns
Some other examples that illustrate practical applications of a pattern
Environments can provide their own host objects, which are not defined in the ECMAScript standard and may have unspecified and unexpected behavior.
The core JavaScript programming language (excluding DOM, BOM, and extra host objects) is based on the ECMAScript standard, or ES for short. Version 3 of the standard was accepted officially in 1999 and is the one currently implemented across browsers. Version 4 was abandoned and version 5 was approved December 2009, 10 years after the previous.
Version 5 adds some new built-in objects, methods, and properties
to the language, but its most important addition is the
so-called strict mode, which actually removes
features from the language, making the programs simpler and less
error-prone. For example the usage of the with
statement has been disputed over the
years. Now in ES5 strict mode it raises an error, although itâs okay if
found in nonstrict mode. The strict mode is triggered by an ordinary
string, which older implementations of the language simply ignore. This
means that the usage of strict mode is backward compatible, because it
wonât raise errors in older browsers that donât understand it.
Once per scope (either function scope, global scope, or at the
beginning of a string passed to eval()
), you can use the following
string:
function my() {
"use strict"
;
// rest of the function...
}
This means the code in the function is executed in the strict subset of the language. For older browsers this is just a string not assigned to any variable, so itâs not used, and yet itâs not an error.
The plan for the language is that in the future strict mode will be the only one allowed. In this sense ES5 is a transitional versionâdevelopers are encouraged, but not forced, to write code that works in strict mode.
The book doesnât explore patterns related to ES5âs specific additions, because at the time of this writing thereâs no browser that implements ES5. But the examples in this book promote a transition to the new standard by:
Ensuring the offered code samples will not raise errors in strict mode
Avoiding and pointing out deprecated constructs such as
arguments.callee
Calling out ES3 patterns that have ES5 built-in equivalents such as
Object.create()
JavaScript is an interpreted language with no static compile-time checks. So itâs possible to deploy a broken program with a simple typing mistake without realizing it. This is where JSLint helps.
JSLint (http://jslint.com) is a JavaScript code quality tool created by Douglas Crockford that inspects your code and warns about potential problems. Itâs highly recommended that you run your code through JSLint. The tool âwill hurt your feelingsâ as its creator warns, but only in the beginning. You can quickly learn from your mistakes and adopt the essential habits of a professional JavaScript programmer. Having no JSLint error in your code also helps you be more confident in the code, knowing that you didnât make a simple omission or syntax error in a hurry.
Starting with the next chapter, youâll see JSLint mentioned a lot. All the code in the book successfully passes JSLintâs check (with the default settings, current at the time of writing) except for a few occasions clearly marked as antipatterns.
In its default settings, JSLint expects your code to be strict modeâcompliant.
The console
object is used
throughout the book. This object is not part of the language but part of
the environment and is present in most current browsers. In Firefox, for
example, it comes with the Firebug extension. The Firebug console has a
UI that enables you to quickly type and test little pieces of JavaScript
code and also play with the currently loaded page (see Figure 1-1). Itâs also highly recommended as
a learning and exploratory tool. Similar functionality is available in
WebKit browsers (Safari and Chrome) as part of the Web Inspector and in
IE starting with version 8 as part of Developer Tools.
Most code examples in the book use the console
object instead of prompting alert()
s or updating the current page, because
itâs an easy and unobtrusive way to print some output.
We often use the method log()
, which prints
all the parameters passed to it, and sometimes dir()
, which
enumerates the object passed to it and prints all properties. Hereâs an
example usage:
console.log("test", 1, {}, [1,2,3]); console.dir({one: 1, two: {three: 3}});
When you type in the console, you donât have to use console.log()
; you can simply omit it. To
avoid clutter, some code snippets skip it, too, and assume youâre
testing the code in the console:
window.name === window['name']; // true
This is as if we used the following:
console.log(window.name === window['name']);
and it printed true
in the
console.
Get JavaScript Patterns now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.