Click here to Skip to main content
14,031,266 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

12.5K views
6 bookmarked
Posted 10 Apr 2014
Licenced CPOL

JavaScript Encapsulation using Anonymous Functions

, 10 Apr 2014
Rate this:
Please Sign up or sign in to vote.
A mechanism to achieve public and private scope for JavaScript objects

Introduction

Developing modern software can become a very complex business. With modern object oriented programming, one of the core principles to reduce complexity is the use of Encapsulation. By hiding private data and functions inside an object (a process known an Encapsulation), we reduce the possible interactions between objects, therefore reducing the complexity of our code.

In languages such as C, C++ and C# encapsulation is built into the language with keywords such as private, protected, public and internal. However, in JavaScript, no such keywords exist so Encapsulation cannot be easily achieved.

However, there is a mechanism to achieve at least public and private scope for JavaScript objects using anonymous functions and the purpose of this article is to guide you through that process. The aim of the article is to allow the user to define and use a class like object in JavaScript, which can be…

  • Created using a constructor like function
  • Can have public and private members
  • Can have multiple instances where each instance contains its own private scope
  • Will encapsulate the internal workings of the object

Anonymous Functions

In JavaScript, programmers can define anonymous functions, which are automatically executed once loaded. The standard way to do this is shown below…

(function () {

    // Code here

} ());

In the section labelled ‘Code here’, we can define as many private functions and variables as we like. Since the code is executed (because of the ‘()’ part on the last line), we can also include lines to execute functions if required.

For example…

(function () {

    // Define a function

    Function HiddenFunction() {
    }

    // Declare a variable

    var variable = {};

    // Execute a function

    HiddenFunction();

} ());

…executes the method ‘HiddenFunction’ when it is loaded.

The purpose of the anonymous function is simply to define and execute some code but the important thing to realise is that the variables and functions contained inside the anonymous function are not visible to the outside world. That is, the variables and functions are private to the anonymous function and this is a feature we can exploit to provide object encapsulation.

Creating a Constructor Function

One of the first goals of the article was to have an object, which could be created using a constructor like function. In the previous section, we saw that we could define private functions in an anonymous function; but how do we define a constructor like function that can be exposed to the outside world?

To solve this, we must first pass in a variable into the anonymous function to allow us to expose our constructor function to the outside world. We can do this by redefining the definition of the anonymous function to be…

(function (window) {

} (window));

The ‘window’ parameter part of the Browser Object Model (BOM), which allows JavaScript to communicate with the browser. Our intention is to add our constructor function to this model so it can be used throughout our JavaScript code. This allows us to export our function to the outside world.

For example, suppose we wanted to create a class called ‘Instance’ and we wanted to expose this to the BOM, we could achieve this with the following code…

(function (window) {

    function Instance() {
    }

    window.Instance = Instance;

} (window));

The line ‘window.Instance’ exposes the local method ‘Instance’ to the BOM using the name ‘Instance’.

Once done, we could create multiple instances of our object by using the following code…

var instance1 = new Instance();
var instance2 = new Instance();

At this stage we have defined our object, we can create multiple instances of our object but our object doesn’t contain any public access functions or internal variables. This will be done later.

Exposing Public Access Functions

The object created previously contains no methods for the user to call. To do this, we must define access methods in the anonymous function and then add them to the ‘prototype’ of our constructor method.

For example, suppose we wanted to add a public access function called ‘Set’, then this could be done by using the following code…

(function (window) {

    function Instance() {
    }

    window.Instance = Instance;

    Instance.prototype.Set = function (newValue) {

        // Implementation code here

    };

} (window));

The definition above adds a public access function called ‘Set’ to the Instance object. The user of the Instance object can then call this method to perform the desired action.

At this stage we have defined our object, we can create multiple instances of the object and our object contains the required public access functions. However, at present, it doesn’t contain any internal variables so the ‘Set’ method cannot do anything.

Adding Instance Specific Data

Even though we can create multiple instances of our object, we have nothing inside our object to contain instance specific data (or variables) and we cannot at present distinguish between multiple instances of our object.

The constructor function for our class is the ‘Instance’ function and to create instance specific data (variables), we must define an object inside this function to contain the instance variables we require. In addition, we need to associate the instance variables with the instance of the object being created; but we don’t want to simply attach the variables directly to the object instance since we want the variables to be encapsulated away.

To solve this problem, we will define a unique id marker inside the variable block. We will also set the id on the object being created so it has a reference back to the variable block. In addition, we will store the variable block internally, using the id as a key, so we can retrieve it later.

The following code shows the implementation of the logic shown above…

(function (window) {

    function Instance() {

        // Create a new variable block for the new object instance
        var variables = {
            // Define a unique id to identify the new object instance
            id: new Date().getTime(),

            // Define variables here...
        };

        // Assign the unique id to new object instance so we can use
        // it to get back to the variables for the new object instance
        this.id = variables.id;

        // Store the variable block for later
        variableStore[this.id] = variables;
    }

    // Variables for object instances

    var variableStore = {};

} (window));

With this logic in place, the public access methods can now use the attached id to get to the correct instance of the object variables as seen below…

(function (window) {

    Instance.prototype.Set = function (newValue) {
        var variables = variableStore[this.id];

        // Perform the change here!
    };

} (window));

Putting It All Together

At this stage, we have explored all of the logic required to use anonymous functions to encapsulate functions and variables inside JavaScript. However, to make it clear, we need to see a concrete example.

The following code implements a class like object that encapsulates a single private variable ('value'). In addition, it only exposes two public methods called 'Set' and 'Get'. The remainder of the logic in the JavaScript object remains hidden to the user…

(function (window) {

    function Instance() {

        // Create a new variable block for the new object instance
        var variables = {
            // Define a unique id to identify the new object instance
            id: new Date().getTime(),

            // Define variables for the new object instance
            value: 0
        };

        // Assign the unique id to new object instance so we can use
        // it to get back to the variables for the new object instance
        this.id = variables.id;

        // Store the variable block for later
        variableStore[this.id] = variables;
    }

    window.Instance = Instance;

    // Variables for object instances

    var variableStore = {};

    // Public methods

    Instance.prototype.Set = function (newValue) {
        Set(variableStore[this.id], newValue);
    };

    Instance.prototype.Get = function () {
        return Get(variableStore[this.id]);
    };

    // Private methods

    function Set(variables, newValue) {
        variables.value = newValue;
    };

    function Get(variables) {
        return variables.value;
    };

} (window));

In addition, the following test code can be used to verify the intended logic of the object…

(function (window) {

    function AreEqual(actual, expected, error) {
        if (actual != expected) {
            alert(error);
        }
    };

    //

    var instance1 = new Instance();
    var instance2 = new Instance();

    AreEqual(instance1.Get(), 0, "Instance1 should equal 0");
    AreEqual(instance2.Get(), 0, "Instance2 should equal 0");

    instance1.Set(10);

    AreEqual(instance1.Get(), 10, "Instance1 should equal 10");
    AreEqual(instance2.Get(), 0, "Instance2 should equal 0");

    instance2.Set(20);

    AreEqual(instance1.Get(), 10, "Instance1 should equal 10");
    AreEqual(instance2.Get(), 20, "Instance2 should equal 20");

    instance1.Set(11);

    AreEqual(instance1.Get(), 11, "Instance1 should equal 11");
    AreEqual(instance2.Get(), 20, "Instance2 should equal 20");

    instance2.Set(22);

    AreEqual(instance1.Get(), 11, "Instance1 should equal 11");
    AreEqual(instance2.Get(), 22, "Instance2 should equal 22");

} (window));

Trying It Out For Yourself

I have added the example code to a Visual Studio 2010 project, together with a HTML file to load the JavaScript files. The project contains the following files…

  • HTMLPage.htm
  • Instance.js
  • TestInstance.js

The HTML page is used to start the project (and should be the active window when F5 is pressed). Its purpose is to simply load the two JavaScript files.

The file “Instance.js” contains the example implementation, which shows how anonymous functions can be used to encapsulate implementation details.

The file “TestInstance.js” calls the example implementation and you can use this file to insert break points for debugging. During the execution, you will be able to see that the use of anonymous functions has indeed encapsulated away nearly all of the implementation details of the object (apart from the id marker!).

Conclusion

This article shows that the use of anonymous functions can successfully be used to encapsulate JavaScript objects. However, the definition presented here is by no means complete. For example, the object id is still visible, when it should be hidden.

In addition, the code presented here is only a framework for JavaScript encapsulation and it would be great to see this work extended to provide features such as inheritance.

History

  • 2014-04-10 – First revision

License

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

Share

About the Author

Experiments
United Kingdom United Kingdom
No Biography provided

You may also be interested in...

Pro

Comments and Discussions

 
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web02 | 2.8.190419.4 | Last Updated 10 Apr 2014
Article Copyright 2014 by Experiments
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid