Click here to Skip to main content
Click here to Skip to main content
Technical Blog

Tagged as

Information Hiding in JavaScript

, 18 Aug 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
How can information hiding be implemented in JavaScript?

info hiding

A key concept in object-oriented programming is information hiding. It refers to the practice of declaring some parts of a class public, and others private, depending on what we want clients of the class to be able to see and do. It protects the application from programmers who may decide to use a class in ways which are contrary to the original intentions of the class’s author.

Unlike object-oriented languages such as Java and C#, the JavaScript syntax does not include keywords such as ‘public’ and ‘private’ (access modifiers) which would allow programmers to practice information hiding quickly and easily. However many programmers, myself included, are used to designing applications based on object-oriented programming, so we need a way to simulate this concept using the features available in the JavaScript language.

There are essentially two ways to do this: using constructor functions, and using the module pattern.

Constructor Functions

I touched on constructor functions in my last post. These are basically functions which are intended to be called with the ‘new’ keyword. By calling a function in this way, we create an object based on the function, with its own state, and where any occurrence of the ‘this’ prefix inside the function will create a public property or function on the created object.

This feature of JavaScript was added to appeal to programmers coming from an object-oriented background, where the ‘new’ keyword is a fundamental feature.

Notice in the example below how the name of the function is capitalized – this is conventional when declaring constructor functions to remind us to treat it as such and to call it with the ‘new’ keyword.

function Rectangle() // capitalized name convention
{
    // private stuff
    var height;
    var width;
    
    // public stuff
    this.getArea = function(){
        return height*width;
    };
    
    this.setWidth = function(w){
        width = w;
    };
    
    this.setHeight = function(h){
        height = h;
    };
    
    this.shapeType = 'rectangle';
}

var rect = new Rectangle(); // use new keyword
rect.setWidth(4);
rect.setHeight(3);
alert(rect.getArea()); // alerts 12
alert(rect.shapeType); // alerts 'rectangle'
alert(rect.height); // alerts 'undefined'

var rect2 = new Rectangle();
rect2.setWidth(10);
rect2.setHeight(2);
alert(rect2.getArea()); // alerts 20
alert(rect2.shapeType); // alerts 'rectangle'
alert(rect2.height); // alerts 'undefined'

Constructor functions also allow us to modify all instances, including ones which have already been created, by updating the function’s prototype property, as shown below.

var rect = new Rectangle();
Rectangle.prototype.numberOfCorners = 4;
alert(rect.numberOfCorners); // alerts '4'

The Module Pattern

The module pattern essentially describes the practice of writing a function which returns an object literal. The function represents our object-oriented class. Any client of this ‘class’ has access only to the object literal returned by the function. Therefore, members defined as part of this object literal are effectively public. Any members declared inside of the function are private, however, they are accessible from the object literal thanks to the concept of closures in JavaScript.

We can see how this works in code in this example.

function getRectangleInstance()
{
    // private stuff
    var height;
    var width;
    
    // public stuff on returned object
    return {
        getArea: function(){
            return height*width;
        },
        setWidth: function(w){
            width = w;
        },
        setHeight: function(h){
            height = h;
        },
        shapeType: 'rectangle'
    };
}

var rect = getRectangleInstance();
rect.setWidth(4);
rect.setHeight(3);
alert(rect.getArea()); // alerts 12
alert(rect.shapeType); // alerts 'rectangle'
alert(rect.height); // alerts 'undefined'

var rect2 = getRectangleInstance();
rect2.setWidth(10);
rect2.setHeight(2);
alert(rect2.getArea()); // alerts 20
alert(rect2.shapeType); // alerts 'rectangle'
alert(rect2.height); // alerts 'undefined'

This variation of the module pattern (there are many), allows us to easily create multiple instances of a class, each of which has its own state.

Which One to Use?

The question of whether to use constructor functions or the module pattern to enforce information hiding in JavaScript is largely a personal choice. In JavaScript – The Good Parts, Douglas Crockford seems to identify constructor functions as a ‘bad part’ of JavaScript, his reasoning being that forgetting to use the ‘new’ keyword when calling a constructor function can lead to unexpected behaviour. However, constructor functions do allow us to easily modify all instances of a class by modifying the function’s prototype property.

Personally, I don’t really see a problem with using constructor functions. Or rather, I don’t see the possibility of forgetting to use ‘new’ as enough of a reason to avoid using them. Just try not to forget! Constructor functions are a powerful feature and they arguably make for more readable code, particularly to those coming from an object-oriented background, not to mention the added advantage of emulating inheritance by accessing the function’s prototype.

As the name suggests, I see the module pattern as being more useful to emulate modules, rather than classes which act as templates for multiple instances. By using the module pattern to define an immediately invoked function expression, we can create a module which is not intended to be instantiated multiple times, but which encapsulates a set of functionality and avoids littering the global namespace. In the example below, we implement the module pattern in this way, declaring an immediately invoked function to assign an object to the shapeModule variable. This object, or module, can contain its own private members, and exposes the getRectangleInstance function, along with any other desired public members. However, by immediately invoking the shapeModule function, we lose the ability to create multiple instances of it. Therefore this variation of the module pattern is often described as emulating the concept of a namespace, rather than a class, in Java or C#.

var shapeModule = function(){
    
    // stuff private to the shape module
    var privateField = 'someValue';
    
    return {
        getRectangleInstance: function(){
            // stuff private to the rectangle instance
            var height;
            var width;
                
            return {
                getArea: function(){
                    return height*width;
                },
                setWidth: function(w){
                    width = w;
                },
                setHeight: function(h){
                    height = h;
                },
                shapeType: 'rectangle'
            };            
        },
        getCircleInstance: function(){
            // code for circles
        }
    };        
}(); // function is immediately invoked

var rect = shapeModule.getRectangleInstance();
alert(rect.shapeType); // alerts 'rectangle'

The important message here is that it is possible, and desirable, to implement information hiding in JavaScript, and once you know how it is not too difficult to do so.

The post Information Hiding in JavaScript appeared first on The Proactive Programmer.

License

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

Share

About the Author

Ronnie Mukherjee
Technical Lead
United Kingdom United Kingdom
I'm a contractor living in Liverpool, UK.
Follow on   LinkedIn

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web01 | 2.8.141015.1 | Last Updated 19 Aug 2014
Article Copyright 2014 by Ronnie Mukherjee
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid