Click here to Skip to main content
15,881,248 members
Articles / Web Development / HTML

Modularization and Encapsulation in JavaScript

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
3 Oct 2017CPOL5 min read 8.8K   49   3  
Implementing modularization and encapsulation in JavaScript

Introduction

Modularization and encapsulation are two important concepts in software development. While both of these concepts are relatively easy to implement in most programming languages, implementing them in JavaScript is not intuitive and requires a more complete understanding of the language itself. The specifications for EMCAScript 2015 (formerly EMCAScript 6) does make implementing these concepts much easier and inline with other languages; however, browser support for EMCAScript 2015 is still incomplete. Modularization can also be achieved with third-party frameworks like Browserfy and RequireJS, which use the CommonJS and Asynchronous Module Definition (AMD) patterns of JavaScript modularization.

Background

Encapsulation is most commonly associated with object-oriented programming (OOP) but the concept itself is in fact separate from it and can be implemented in the absence of any OOP pattern, including prototypal, as is the case in JavaScript. The two notions that define this concept are:

  1. bundling the data with the methods of a module and
  2. restricting direct access to a module's components

The intent of the first notion is to prevent the user of the module from setting the module into an invalid or inconsistent state that was not intended by the module's creator. Both notions make code more understandable and maintainable which can be considered the most important concept of all, particularly from a developer's point of view.

Modularization provides another way to develop code that is more understandable and maintainable. In addition, it prevents real-time issues that can occur with namespaces by keeping components (and associated code) out of the global namespace where one code component may inadvertently override the implementation of another if the names are the same (for example, two functions with the same name). Using third-party frameworks and libraries can really increase the potential for these issues which is why most of them implement modularization.

The Code

In order to demonstrate a real-world example of these concepts, I have created a very usable set of components that partially mimic the .NET implementation of a generic list collection with LINQ support (see this link for an understanding of LINQ with .NET). The code for this is attached to this article. Most of the code used below in this article is taken directly from this implementation.

Modularization is achieved with the use of anonymous function expressions as opposed to function declarations. As seen in the code below, adding a set of parenthesis at the end of the function definition will make it a function expression which is executed immediately when the code is loaded (any functions inside the module are NOT executed immediately). An anonymous function in and of itself will not provide modularization since no 'name' is provided in the namespace (in this case the global namespace), which is why we declare a global variable (in this case, it is named 'Zenith'), pass that variable into the anonymous function and assign any components to it in the function implementation. The important idea to take away here is that the name 'Zenith' is added to the global namespace and is required to access any of the components inside of it; thus, keeping these components out of the global namepsace. Also note that nothing prevents the developer from creating namespaces within namespaces which could keep an entire namespace out of the global scope.

JavaScript
var Zenith;

(function (Zenith) {

    function List() {

    };

    Zenith.List = List;

})(Zenith || (Zenith = {}));

In the above example, the List function can only be accessed in JavaScript code by first providing the Zenith module name as follows:

JavaScript
var list = new Zenith.List();

Note the code inside the parentheses at the end of the function definition:

JavaScript
Zenith || (Zenith = {}

This pattern allows you to add any number of components to a namespace just by adding additional anonymous functions and passing the same global variable (acting as the namespace name) in as a parameter. For example:

JavaScript
(function (Zenith) {

    function LinkedList() {

    };

    Zenith.LinkedList = LinkedList;

})(Zenith || (Zenith = {}));

Now, in addition to creating a List component in the same code base, we can also create a LinkedList component as follows:

JavaScript
var list = new Zenith.LinkedList();

You may hear different terms for different module patterns. Strictly speaking, this pattern is called the Revealing Module Pattern because all of the components inside the module are by default private (and cannot be accessed from outside the module) but assigning these components to the 'outside' (global) variable makes them public.

Encapsulation can be achieved using functions in JavaScript and it requires a partial understanding of the this keyword in JavaScript. Please note that the this keyword is more complicated than its use described here. When used in a function, it refers to the object that was created using the function. This is easier to understand when you realize that a function is actually an object in JavaScript. Here is an example:

JavaScript
function List(initialArray) {

    var listArray = initialArray || [];

    this.Count = function () {
        return listArray.length;
    };
}

var list = new List();
var list2 = new List();

In the above example, list and list2 end up as variables that refer to two different objects created using the List function. Each one contains a listArray variable and a Count method. The this property will refer to the corresponding object. (In this example, it is actually unnecessary and wasteful to create the Count method for every object since the code will be the same for every object; however, avoiding this requires the implementation of prototypal inheritance in JavaScript which is outside the scope of this article).

As you can see, the first notion of encapsulation is achieved since the data and method is bundled with each object. The second notion is not so intuitive here but is nonetheless easy to implement with just a little bit of knowledge. Using the this keyword (property) when defining a property or method makes the property or method public, or accessible from outside the function. All variables or methods not defined using the this keyword are private. So, in the above example, the variable listArray for each object is private and the Count method is public. Simple as that!

History

  • 10/3/2017: Initial version submitted for approval
  • 10/4/2017: Second version submitted for approval

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
For over 25 years I have worked in the Information Systems field as both a full-time employee and an independent contractor for a variety of companies.

I have extensive professional experience with numerous programming languages and technologies including C#, JavaScript, SQL, VB.NET, and ASP.NET as well as a working knowledge of a great variety of others. I also have an advanced understanding of the concepts behind these technologies including Object-Oriented Programming, Relational Data, Functional Programming, MVC and MVVM.

Some of my more recent work has been designing and building web applications primarily with JavaScript in conjunction with many of the JavaScript libraries/frameworks including jQuery, KnockoutJS and Bootstrap and consuming both JSON and REST services.

In nearly all of the work I have been involved with in the past ten years I have played a lead role in the design as well as the development of the work. More recently I have managed a team of software developers at a local mid-size company.

Comments and Discussions

 
-- There are no messages in this forum --