for object creation.
The JavaScript language is simple and straightforward and often there’s no special syntax for features you may be used to in other languages, such as namespaces, modules,packages, private properties, and static members. This chapter takes you through common patterns to implement, substitute, or just think differently about those features.
We take a look at namespacing, dependency declaration, module pattern, and sandbox patterns—they help you organize and structure your application code and mitigate the
effect of the implied globals. Other topics of discussion include private and privileged members, static and private static members, object constants, chaining, and one class-
inspired way to define constructors.
Namespace Pattern
// BEFORE: 5 globals
// Warning: antipattern
// constructors
function Parent() {}
function Child() {}
// a variable
var some_var = 1;
// some objects
var module1 = {};
module1.data = {a: 1, b: 2};
var module2 = {};
You can refactor this type of code by creating a single global object for your application,called, for example, MYAPP, and change all your functions and variables to become properties of your global object:
// AFTER: 1 global
// global object
var MYAPP = {};
// constructors
MYAPP.Parent = function () {};
MYAPP.Child = function () {};
// a variable
MYAPP.some_var = 1;
// an object container
MYAPP.modules = {};
// nested objects
MYAPP.modules.module1 = {};
MYAPP.modules.module1.data = {a: 1, b: 2};
MYAPP.modules.module2 = {};
For the name of the global namespace object, you can pick, for example, the name of your application or library, your domain name, or your company name. Often developers use the convention of making the global variable ALL CAPS, so it stands out to the readers of the code. (But keep in mind that all caps are also often used for constants.)
page, such as JavaScript libraries or widgets. This pattern is highly recommended and perfectly applicable for many tasks, but it does have some drawbacks:
• Only one global instance means that any part of the code can modify the global instance and the rest of the functionality gets the updated state
• Long nested names mean longer (slower) property resolution lookups
General Purpose Namespace Function
// unsafe
var MYAPP = {};
// better
if (typeof MYAPP === "undefined") {
var MYAPP = {};
}
// or shorter
var MYAPP = MYAPP || {};
You can see how these added checks can quickly result in a lot of repeating code. For example, if you want to define MYAPP.modules.module2, you’ll have to make three checks, one for each object or property you’re defining. That’s why it’s handy to have a reusable function that takes care of the namespacing details. Let’s call this function namespace() and use it like so:
// using a namespace function
MYAPP.namespace('MYAPP.modules.module2');
// equivalent to:
// var MYAPP = {
// modules: {
// module2: {}
// }
// };
Next is an example implementation of the namespacing function. This implementation is nondestructive, meaning that if a namespace exists, it won’t be re-created:
var MYAPP = MYAPP || {};
MYAPP.namespace = function (ns_string) {
var parts = ns_string.split('.'),
parent = MYAPP,
i;
// strip redundant leading global
if (parts[0] === "MYAPP") {
parts = parts.slice(1);
}
for (i = 0; i < parts.length; i += 1) {
// create a property if it doesn't exist
if (typeof parent[parts[i]] === "undefined") {
parent[parts[i]] = {};
}
parent = parent[parts[i]];
}
return parent;
};
This implementation enables all of these uses:
// assign returned value to a local var
var module2 = MYAPP.namespace('MYAPP.modules.module2');
module2 === MYAPP.modules.module2; // true
// skip initial `MYAPP`
MYAPP.namespace('modules.module51');
// long namespace
MYAPP.namespace('once.upon.a.time.there.was.this.long.nested.property');
Declaring Dependencies
desired module: