Creating objects in JavaScript is quite simple - just use the object literal or call the constructor function. Here we will introduce a few additional tricks used to create objects.
Object Creation Templates
The JavaScript programming language is simple, and lacks many specialized syntax constructs available in other languages, such as namespaces, modules, packages, private properties, and static members. Here you will learn about common templates that allow you to implement or simply present all these features in a different way.
We will get acquainted with the methods of creating namespaces and modules, with the possibility of declaring dependencies and allocating an isolated namespace. All this will help you organize and structure the program code in applications and weaken the influence of the mechanism of implied global variables.
Namespaces
Namespaces eliminates usage of global variables that our programs need, while avoiding name conflicts and overuse of prefixes.
JavaScript syntax lacks namespace definition constructs, but this feature is easy to implement in other ways. Instead of clogging the global namespace, you can create single global object that will serve as the namespace for the application. After that, you can add all the necessary functionality to this object.
Take a look at the following example:
// BEFORE: 5 global variables
// Warning: anti-pattern
// constructors
function Car() {}
function Person() {}
// variable
var my_var = "blue";
// pair of objects
var my_module1 = {};
my_module1.data = {first_name: "Greg", last_name: "Movses"};
var my_module2 = {};
Such program code can be easily rewritten in another way, creating a single global object, let`s call it MYAPP, and turning all functions and variables into properties of this global object:
// AFTER: 1 global variable
// global object
var SOFTXPATH = {};
// constructors
SOFTXPATH.Car = function() {};
SOFTXPATH.Person = function() {};
// variable
SOFTXPATH.my_var = "blue";
// container object
SOFTXPATH.my_modules = {};
// nested objects
SOFTXPATH.my_modules.my_module1 = {};
SOFTXPATH.my_modules.my_module1.data = {first_name: "Greg", last_name: "Movses"};
SOFTXPATH.my_modules.my_module2 = {};
As the name of a global namespace object, you can choose, for example, the name of your application or library, the domain name or the name of your company.
Often developers follow a naming convention that global variable names are constructed only from CAPITAL CHARACTERS, thanks to which they will immediately catch the eye of those who will read the program code (But keep in mind that the same convention is often used when choosing names for constants).
This template provides the ability to create namespaces for your program code and avoids name conflicts both within your applications and between your program code and third-party libraries.
This template is great for most tasks, but it has some disadvantages:
- The amount of input from the keyboard increases, since you have to prefix each variable and each function, which as a result increases the size of the downloaded file.
- The presence of a single instance of a global object implies that any part of the program code can make changes to it, while the rest of the program code will use the changed object.
- Extending the names of nested variables implies an increase in the time required for resolving names.
These shortcomings are addressed by the isolated namespace pattern, which is discussed below.
A universal function for creating a namespace.
With the increasing complexity of the program, some fragments of the program code have to be taken out into separate files and imported under certain conditions.
As a result, it becomes unreasonable to assume that your file is the first to define some namespace or property in it. It is possible that some of the properties that are supposed to be added already exist, and you can overwrite them by negligence.
Therefore, before adding a property or creating a namespace, it is advisable to make sure that it has not yet been created, as shown in the following example:
// unsafe way
var SOFTXPATH = {};
// that`s better
if (typeof SOFTXPATH === “undefined”) {
var SOFTXPATH = {};
}
// or a little shorter
var SOFTXPATH = SOFTXPATH || {};
It`s easy to understand that such checks can quickly turn into a huge amount of repetitive code. For example, if you want to create the MYAPP.modules.module2 property, you will need to perform three checks, one for each object you create.
Therefore, it would be very convenient to have a function that would carry out all the operations necessary to create a namespace.
We call this function createNameSpace() and assume that it should be used as shown below:
// use the namespace function
SOFTXPATH.createNameSpace(‘SOFTXPATH.my_modules.my_module2’);
// this call is equivalent to the following construct:
var SOFTXPATH = {
my_modules: {
my_module2: {}
}
};
The following is an example of the implementation of this function, in which the principle of non-destruction is used, that is, if the namespace with the given name already exists, it will not be recreated:
var SOFTXPATH = SOFTXPATH || {};
SOFTXPATH.createNameSpace = function(ns_string) {
var modules = ns_string.split(‘.’),
root = SOFTXPATH,i;
// discard the initial prefix - the name of the global object
if (modules[0] === “SOFTXPATH”) {
modules = modules.slice(1);
}
for (i = 0; i < modules.length; i + = 1) {
// create a property if it is missing
if (typeof root[modules[i]] === “undefined”) {
root[modules[i]] = {};
}
root = root[modules[i]];
}
return root;
};
Such an implementation makes all of the following uses of the function valid:
// assign the return value to a local variable
var my_module2 = SOFTXPATH.createNameSpace(SOFTXPATH.my_modules.my_module2’);
my_module2 === SOFTXPATH.my_modules.my_module2; // true
// omit the initial prefix `SOFTXPATH`
SOFTXPATH.createNameSpace(my_modules.my_module51’);
// create deeply nested namespaces
SOFTXPATH.createNameSpace(‘my_modules.xml.getChildrenByType.getFirst’);