How do you Declare Namespace in JavaScript?
A namespace is a separate scope for variables, functions, and types to prevent overwriting of variables and functions or preventing name conflicts. Namespacing is the practice of creating an object which encapsulates functions and variables that have the same name as those declared in the global scope. A namespace can be declared in multiple ways and the most common way of declaring a namespace involves creating an object.
Syntax
The syntax for creating a namespace in javascript is as follows,
The keyword may be var, let, or const. Please note that, when the const variable is used, the namespace cannot be altered or modified after declaration. Therefore, the const keyword is only used when the namespace is well-defined during the time of its declaration.
Is JavaScript namespace Necessary?
Javascript namespace is necessary and can be found in any industrial javascript program. The following factors make the javascript namespace necessary,
- Namespace prevents the pollution of the code base and makes the code cleaner and easy to understand.
- It prevents unexpected collision of variables or functions.
- Overriding a function or variable is possible if everything is declared in the global namespace. This will not result in a compiler error but gives logical errors.
- Namespace becomes very essential while dealing with third-party libraries, as we may override the functions in those libraries.
- It is an ideal programming approach to use a namespace and it also helps in debugging the program.
Single Global Variables
A method to perform namespacing in javascript is using a single global variable as the namespace variable. We can use this variable to access the variables or functions that are provided access to the user in the namespace.
Code :
Output:
Explanation:
In the above example, a self-invoking function is used to create a namespace and assign the namespace to a global variable, namespace and we can use this variable as a reference to use the methods and variables returned by the self-invoking function. The following image illustrates the structure of the above example,
The advantages of this method are that it is easy to use and is modular as the return statement act as a public interface to the namespace and prevents access to the privateFunction. The main problem in using this method is that we must ensure that there are no two global variables with the same name.
Note : A self-invoking function in javascript is a function that is called by itself without the need to be invoked externally. The syntax of the self-invoking function is,
Prefix Namespacing
The prefix namespacing method to create a namespace is much simpler than the previous method. Unlike creating a physical namespace by using objects or functions, we create a logical namespace by using the same prefix for variables and functions present in the same namespace.
Code: Namespacing with prefix
Output:
In the above example, the prefix ns, is used to logically mark a namespace in which objectA , objectB, and the ns_privateMethod() function are present. The following image illustrates the structure of the above example,
One disadvantage of this method is that it can pollute the code base with many global variables.
Object Literal Notation
The object literal notation of creating a javascript namespace involves using an object literal to enclose the functions and variables that belong to that namespace. The object name can be further used to access all the members of the namespace.
Code: Creating an Object Literal
Output:
Explanation:
In the above example, the Student object works as a namespace for all the members inside the Student object. To access any members inside the namespace, we need to call it using the Student object such as Student.ID or Student.get_Grade(). The following image illustrates the structure of the above example,
The above example can also be implemented by creating the object first and adding the members of the object afterward. The following code illustrates this,
In the above code snippet, the members are added to the Student object gradually. The main advantage of this method is that the pollution of the code base by global objects is prevented and the way of representation makes the code easier to read.
We can always check for the existence of an object namespace before creating that object namespace. The following methods can be used to check the presence of the object literal in the global object,
Code: Using the logical OR operator
In the above method, the logical operator checks for the existence or declaration of the sample_ns and if the sample_ns is not found, the sample_ns will be declared and assigned to {}.
It is important to note that only the keyword var can be used in this case, as the keyword let doesn't allow to redeclare variables and is also block scoped. The keyword var also supports hoisting, a mechanism by which the variables declared using var will be moved to the top scope of the program which is not provided by let.
Code: Using if condition
The ! symbol is used to negate and check for the presence of sample_ns. If sample_ns is not present, then the ! operator negates the values, the if condition returns true, and the if statement block will be executed.
Code:
The window object holds all the global members of the javascript program. In the above code snippet, we are checking if the sample_ns is present in the window object and sample_ns is created if it is not found.
Code: Using the undefined keyword
The data type of sample_ns is compared with the primitive undefined and a conditional operator is used to assign the value of sample_ns if it is not found.
Note : The undefined primitive is used to represent variables that have not been assigned any value.
Nested Namespacing
Nested namespacing is used to extend a namespace and create a namespace inside another namespace.
Code: Implementing nesting of namespace
Output:
Explanation:
In the above example, sample_ns is a normal namespace created using the object literal method, and the sample_ns.nested_ns is the nested namespace. The deep_nested is another object that lies inside the sample_ns.nested_ns namespace that stores all the members in the namespace. The following image illustrates the structure of the above example,
The following code snippet shows how a nested namespace can be created very easily,
The main advantage of the nested namespace is that many complex representations of data can be made and collision of names can be avoided. The problem with this method is that it increases the lookup or search time to find a member in the namespace. For example, consider the following hierarchy of namespaces,
If we want to find a member in the deep_nested namespace, we would have to search through sample_ns, nested1, and nested2 in a hierarchical order before searching the deep_nested namespace. This results in a lot of time complexity which may be not favored in the program.
Immediately-Invoked Function
We have already seen the self-invoking function in javascript in the above sections. Now, the same concept can be used to generate a namespace at the start of the execution of the program.
Code:
Output:
Explanation:
In the example above, an empty namespace named function_ns is created first and then the namespace is passed as an argument to the self-invoking function to add the members and functions inside the namespace. Inside the function, the parameter variable temp_ns is used to represent the namespace. The following image illustrates how the immediate-invoked function is used to create the namespace,
The advantage of this method is that it can be used to extend the namespace with members easily.
Expressions
It is possible to create an alias for very long nested namespaces.
Code:
Output:
Explanation:
In the above code, the nested namespace nameSpace.Browser.JavaScript.OOPS have been expressed with the variable expression and we can access all the elements of the nested subset with this variable.
Namespace Injection
Using namespace injection, methods and properties can be injected into a namespace using the this property. The self-invoking functions are used to apply the changes to the namespace.
Code: Injecting members to namespace
Output:
Explanation:
In the above example, innject_ns is a simple namespace, and innject_ns.sub is a nested namespace which is provided as an argument into the apply() method of the immediate invoking function. The this represents this namespace inside the function and using the this keyword new nested namespace and data members can be introduced.
Namespace with Argument
The namespace can be sent as an argument to an immediate invoking function to create a nested namespace or create data members in the namespace.
Code:
Output:
Explanation:
In the above example, two levels of nested namespaces are created by passing a namespace as an argument to an immediate invoking function. The function_ns.nest.deep_nested.name represents the name variable in the deep_nested object of the nest nested namespace.
Advantages of JavaScript namespace
- The javascript namespace provides a methodology to isolate the code and organize it.
- It helps to avoid name collisions and overriding of functions or variables.
- Due to the well-organized nature of the namespace, the code becomes easy to understand.
- Allows us to model different relationships using nested namespaces.
- Prevents memory leakage due to accidental global variables.
Conclusion
- Namespace provides a separate scope to work with and also avoids name collisions and overriding of functions.
- It is best practice to use a namespace when the code gets very long.
- There are many ways to create a namespace and most easy way is using an object literal.
- Immediate invoking functions can be used to create a namespace or add data members to a namespace.
- Nested namespace provides the namespace with a feature to extend and represent many members.
- An efficient programming approach can be made by using the required amount of namespacing.