Loading...

Patterns in JavaScript

Module Pattern

Objects that a developer wishes to keep private can be indicated with an underscore. Look at an account data Object, for example. This would likely house sensitive data. The caution needed when handling this object is often relayed with an underscore at the beginning of the name like this: _accountData. This will signal to future developers they should use Accessor properties to access data in this object instead of directly accessing the data. The problem here is that a future developer may not understand this and can still access the Object directly. To address this potential problem here, as well as similar sensitive data situations, the developer can use the Module Pattern approach.

In JavaScript, classes can work as the module as they protect information from being accessed through encapsulation. In general, the idea is to invoke the module immediately through a process known as IIFE (Immediately Invoked Functions Expression). IIFE's are used to keep data within the function scope private and return only public data making that all that can be directly accessed.

Invoking a function immediately can be accomplished the same way as any function; that is to use ( ).  In this case, the function has no name and passes another anonymous function as an argument, and then is invoked right after declaring. It looks like this: (function() { ...code })()

Note: IIFE only works because () is an expression. This will not work on function declarations like this: function myFunctName() { ...code }

Basic Structure

This is wrapped in (), returns public data and invokes immediately using the () right before closing.

const myObject = (function() {
    // ...here is where private data variables can live        

    return {
        //    ...public methods and properties reside here
    };
    //    NOTE: This contains a () in the closing below. This invokes this function immediately
}());



↓Example ↓
const account = (function() {
    // Private data
    let balance = 1000;

    return {
        //    Public data
        name: "John",
        getBalance: function() {
            return balance //    balance is available as this function reside within the function scope.
        },
        addINterest: function(interest) {
            balance += interest;
        }
    };
}());

console.log(account.name); //    RESULT: "John"
console.log(account.getBalance()); //    RESULT: 1000
account.balance = 2000; //    RESULT: balance can not be changed as it is locked within the functions's scope.
console.log(account.getBalance()); //    RESULT: 1000 because it could not be changed.
console.log(account.addINterest(300)); //    RESULT: 300 is added to balance because addINterest is inside of the function scope.
console.log(account.getBalance()); //    RESULT: 1300 because this was changed with addINterest()

Revealing Module Pattern

Revealing Module Pattern is similar to the processes described above, but different in that the public and private code can be kept together

Below is the general structure. This is wrapped in (), returns public data and invokes immediately using the () right before closing.

const myObject = (function() {
    // ...here is where private data variables can live        
    privateVar = data;
    functionName1() {
        ...
    };
    functionName2() {
        ...
    };

    return {
        //    ...public methods and properties reside here
        //    The functions detailed in the private area can be made public via the return
        functionName1: functionName1,
        functionName2: functionName2
    };
    //    NOTE: This still contains a () in the closing to invoke this function immediately
}());


↓ Example ↓
const account = (function() {
    // Private data
    let balance = 1000;

    function getBalance() {
        return balance //    balance is available as this function reside within the function scope.
    };

    function addINterest(interest) {
        balance += interest;
    };

    return {
        //    Public data
        name: "John",
        getBalance: getBalance,
        addINterest: addINterest
    };
}());

console.log(account.name); //    RESULT: "John"
console.log(account.getBalance()); //    RESULT: 1000
account.balance = 2000; //    RESULT: balance can not be changed as it is locked within the functions's scope.
console.log(account.getBalance()); //    RESULT: 1000 because it could not be changed.
console.log(account.addINterest(300)); //    RESULT: 300 is added to balance because addINterest is inside of the function scope.
console.log(account.getBalance()); //    RESULT: 1300 because this was changed with addINterest()

A great in-depth look at Module Pattern can be found here ->

Prototype Pattern

In situation where large database queries or similar operations are needed multiple times, there can be a tremendous performance boost to make a copy of the original instead of running the whole process again. This is what the Prototype Pattern attempts to accomplish. Ultimately, a shallow clone is made of the original Object. To ensure the variables and methods bind to the object's structure, the keyword prototype is used.

var appleSauce= function() {
 this.apples    = 4;
 this.tool = 'masher';
 this.spices= 'cinnamon';
}

appleSauce.prototype = {
 mash: function() {
    // Mash the apples
 },
 mix: function() {
    // Mix in the spices
 }
}

Revealing Prototype Pattern

This variation is similar to the Prototype Pattern described above, but different in that the public and private code can be kept together


var appleSauce= function() {
 this.apples    = 4;
 this.tool = 'masher';
 this.spices= 'cinnamon';
}

appleSauce.prototype = {
 const mash = function() {
    // Mash the apples
 },
 const mix = function() {
    // Mix in the spices
 }

 return {
    mashTheApples : mash ,
    mixInSpices: mix
 }

}();

Observer Pattern

There are times when something changes prompting the need for a change elsewhere. The Observer Pattern keeps watch for a specific change and then broadcasts a notice to another part of the program. For this, you need an Observer and a Subject. The Subject is an object that keeps a list of dependents. These dependents are the Observers. The Subject will then call a method or similar action to notify the Observers of a change.

The following are required on the Subject class:

  • observers property– This holds an array of observers.
  • addObserver() method – Pushes an observer onto the observer’s array.
  • removeObserver() method – Removes an observer from the observer’s array.
  • notify() method – Lets all of the observers know that there has been a change.
var Subject = function() {
 this.observers = [_];

 return {
    subscribeObserver: function(observer) {
     this.observers.push(observer);
    },
    unsubscribeObserver: function(observer) {
     var index = this.observers.indexOf(observer);
     if(index > -1) {
        this.observers.splice(index, 1);
     }
    },
    notifyObserver: function(observer) {
     var index = this.observers.indexOf(observer);
     if(index > -1) {
        this.observers[index].notify(index);
     }
    },
    notifyAllObservers: function() {
     for(var i = 0; i < this.observers.length; i++){
        this.observers[i].notify(i);
     };
    }
 };
};

var Observer = function() {
 return {
    notify: function(index) {
     console.log("Observer " + index + " is notified!");
    }
 }
}

var subject = new Subject();

var observer1 = new Observer();
var observer2 = new Observer();
var observer3 = new Observer();
var observer4 = new Observer();

subject.subscribeObserver(observer1);
subject.subscribeObserver(observer2);
subject.subscribeObserver(observer3);
subject.subscribeObserver(observer4);

subject.notifyObserver(observer2); // Observer 2 is notified!

subject.notifyAllObservers();
// Observer 1 is notified!
// Observer 2 is notified!
// Observer 3 is notified!
// Observer 4 is notified!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

q
↑ Back to Top