JavaScript Module Pattern

Modules are needed in JavaScript to achieve modularity, which is to keep pieces of code that is unrelated to be independent from one another in a loosely coupled way (changes in one affects little to no effects to another).

These sort of module patterns are popular when module bundler like Webpack is still not a thing.

Modularity is considered by many to be well-structured code.

It's the idea of separation of concern. Revolves around the principle of high cohesion and low coupling.

Module provides encapsulation and avoid namespace collision. It acts as a replacement of class.

Encapsulation is something that JavaScript natively doesn't have. To counter this, we use something called closure. It provides private variable/method.

To sum that:

  • provide encapsulation

  • support modularity

  • avoid namespace collision

Module design pattern uses something referred to as IIFE (immediately invoked function expression), it's simply a function that wraps inside of a parentheses.

let iife = (function () {  
  ...
})();

or,

let iife = (function () {  
  ...
}());

The parentheses tells JavaScript engine that what's inside has to be an expression, therefore it knows when it encounters a function, the function has to be a function expression, not a function declaration.

There is also an important feature JavaScript has that you need to know, it is known as implied globals.

On a non global execution context, let's say something like this:

function foo () {  
  undeclaredVar = 3;
}
foo();  
console.log(undeclaredVar); // outputs 3  

Although undeclaredVar has not been declared prior, it still works!

JavaScript engine will check whether undeclaredVar is available in the current execution context, if not, then it will check it's parent execution context and see if it's there. If it's fruitless, then JavaScript engine will treats it as a global variable (freshly created with the corresponding assignment as the value).

Bear in mind that implied globals will not work in the global execution itself on strict mode!

a = 3; // throws error  
Revealing Module Pattern

This is the basic module pattern you'll use and often see to create a module. You probably saw it in another types of pattern (not just module pattern) such as factory.

let awesomeModule = (function () {  
  // private variable goes here
  return {
    // public variable goes here
  };
})()
Privilege Member

Privilege members are used to access private members indirectly. It's like a setter and getter. An advantage is to be able to filter and protect private members for being accidentally altered with an unexpected value or solely errors.

let awesomeModule = (function () {  
  let numFoods = 10;
  return {
    setFood(numFood) {
      if (typeof numFood !== 'number') {
        throw Error('setFood require number parameter');
      }
    }
  };
})()
Augmentation

This is a module pattern used to add additional properties to our current module. It is divided into two distinct variance:

  • Loose augmentation

  • Strict augmentation

Tight augmentation requires module to load synchronously (in order), while strict augmentation does not.

Tight Augmentation:
let module = (function (module) {  
  module.newProp = 'bar';
  module.newMethod = () => {};
  return module;
})(module)

So it is no longer creating but instead adding.

Notice that is passes module, therefore module needs to already been initialized (otherwise it will be undefined).

I don't really know the importance of returning and reassigning the module on this pattern. I guess it's purpose is generally consistency.

Loose Augmentation:
let module = (function (module) {  
  module.newProp = 'bar';
  module.newMethod = () => {};
  return module;
})(module || {})

Loose augmentation does not requires you to provide an existing module.

Now in this case, it is important to return the module and reassign it, just in case that the module does not exist in the first place. Otherwise, no augmenting will ever takes place.

As for the expression module || {} it will returns {} when module is falsy. You can think {} as a default.

The only downside is incapability to overwrite methods.

Sub-Module

Nothing special here, creating a sub-module is as simple as creating a module:

module.subModule = (() => {  
  return {};
})()

Brief Note on JavaScript Promises and Async/Await

Promise has the following syntax:

new Promise((resolve, reject) => {  
  // code goes here...
});

Invoking resolve() will returns a resolved promise.

let resolvedPromise = new Promise((resolve, reject) => resolve());  

Invoking reject() will returns an rejected promise.

let resolvedPromise = new Promise((resolve, reject) => reject());  

Throwing an error inside a .then will returns a rejected promise:

  Promise.then(() => throw new Error());

.then() will be executed if prior promise resolves, returns a rejected promise if prior promise is rejected.

.catch() will be executed if prior promise rejected, returns a resolved .

An unhandled rejected promise will not stop execution context from running, and is not handled the way normal throws (in try catch block).

Async function must yield (await) a promise!

Invoking an async function will returns a promise that resolves when the async function returns (pop), resolved with the returned value from the async function itself.

async().then((resolvedVal) => console.log(resolvedVal))  

If the returned is a promise, then it will resolved when the returned promise as in:

.then(() => new Promise((res, rej) => 2))

If none is explicitly returned, then it returns undefined as the resolved value.

Async functions are generators, which means it yields, where yield is equivalent to await. And it must yield a promise.

If the yielded promise resolves, it will continue executing the async function and pass along the resolved value back to it.

If it yields a promise that is rejected, the async function will returns with a rejected promise.

I currently have no idea how a async as a generator knows when it is done internally. What I mean is:

async function a() {  
  await new Promise((resolve, reject) => resolve());
  console.log('foo');
}
a().then((res) => console.log('bar'));  

This will outputs foo and bar respectively.

I was thinking that when it yields an object where .done() is true, then the async function will resolved, but apparently that is not the case.

JavaScript Design Pattern

Pattern is something I heard a lot in the developer community. Might be awesome to get some deeper insight what it actually is.

Without further ado, lets dive together on learning Design Patterns! I'll be using Addy Osmani's book, Learning JavaScript Design Patterns*, as a reference.

What is a Pattern, anyway?

Patterns are proven approach on solving over a recurring problems we might encounter during code production.

It matters because it has been tested over and over again on lots of scenarios.

Rather than having to write our own approach only to realize that it's not working as you might expected. Not saying that you shouldn't, but it would be wiser in terms of efficiency and effectivity to use an existing pattern.

Addy Osmani state the following advantages of pattern on his book, JavaScript Design Patterns:

  • Preventing minor issues (edge cases).

  • Applicable to lots of scenarios (not tied to a specific problem).

  • May decrease file size by reducing repetition also known as DRY (don't repeat yourself).

  • Add to a developer's vocabulary.

  • Improved over time through collective experience.

Know It's Brother

Design Pattern has it's opposite, named anti-pattern.

Well, as you might guess, it is a pattern that sucks!

Apparently it has been known for quite some time that using an anti-pattern leads to destruction.

So it might be better to just avoid it.

An example of anti-pattern is using document.write due it's capability to overwrite your whole document. Disaster indeed.

Patterns Into Sections

Patterns generally divided into three major classifications:

  • Creational

  • Structural

  • Behavioral

Take a closer look of the following image (taken from Slideshare):
JavaScript Design Pattern

I'll be covering each and every one of these into several blog posts.

Pattern Table of Content

JavaScript Constructor Pattern

There are 3 ways to create an object in JavaScript:

let object1 = {};

let object2 = Object.create(Object.prototype);

let object3 = new Object({key: val, ... });  

The first option is an object literal where basically is a key-value pair.

The second lets you specify the prototype for the object you're trying to create. You'll able to see it by accessing object2.__proto__. You'll need to specify the prototype or otherwise it will throws.

Remember that every object inherits Object.prototype by default.

So for instance, object1.__proto__ will be equivalent to Object.prototype without be obliged to specify the prototype by yourself. But for the second option, you'll be needing to sepcify Object.prototype by yourself.

The following achieve the same result as the third option:

Object({key: val, ... });  
Accessing and Mutating Props

You'll mainly use either dot notation . or a bracket notation [].

For setting/assigning a new property, you can also use Object.defineProperty(), by the following syntax:

Object.defineProperty(obj, prop, descriptor)  

There are two type of descriptor, you can only choose either of these, otherwise it will throws.

  • data descriptor
  • accessor descriptor

Both have the following key:

  • configurable: are the descriptor mutable?
  • enumerable: will the property shows up during enumeration (for ... in and Object.keys).

For data descriptor:

  • value: well, the value for the property.
  • writable: is the property mutable?

Ex:

Object.defineProperty(obj, 'awesomeKey', {  
  enumerable: false,
  configurable: false,
  writable: false,
  value: 'Some random awesome value'
});

There are defaults for every of these descriptor keys, so you don't have to explicitly specify for each.

But if you don't, there is a possibility where the options are inherited from the prototype chain. I'm not really sure about this, though...

For accessor:

  • get
  • set

Both get and set are function that will be executed when you either assign or access the corresponding key. For instance:

let Cat = {};  
Object.defineProperty(Cat, 'age', {  
    get: function() {
      return this.age || 10;
    },
    set: function(value) {
      this.age = value;
    }
  });

console.log(Cat.age); // returns 10  
Cat.age = 12;  
console.log(Cat.age); //returns 12  

Why Redux Use Pure Function

Before going straight to the question, let us steal a piece of code from Redux that features combineReducers() function.

It seems that my previous understanding on how Redux implements combineReducers() does not aligns with the current implementation.

Here's my prior understanding on how it works:

const combineReducers = (reducers) => {  
  return (state = {}, action) => {
    return Object.keys(reducers).reduce(
     (nextState, key) => {
       nextState[key] = reducers[key](
         state[key],
         action,
       );
       return nextState;
     },
     {});
  }
}

Current Implementation:

var reducerKeys = Object.keys(reducers);  
var finalReducers = {};  
for (var i = 0; i < reducerKeys.length; i++) {  
  var key = reducerKeys[i];
  finalReducers[key] = reducers[key];
}
var finalReducerKeys = Object.keys(finalReducers);

return function combination() {  
    var state = arguments[0];
    var action = arguments[1];

    var hasChanged = false;
    var nextState = {};
    for (var i = 0; i < finalReducerKeys.length; i++) {
      var key = finalReducerKeys[i];
      var reducer = finalReducers[key];
      var previousStateForKey = state[key];
      var nextStateForKey = reducer(previousStateForKey, action);
      if (typeof nextStateForKey === 'undefined') {
        var errorMessage = getUndefinedStateErrorMessage(key, action);
        throw new Error(errorMessage);
      }
      nextState[key] = nextStateForKey;
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
    }
    return hasChanged ? nextState : state;
  };

Note: several lines of code are stripped for simplicity sake.

As you can see it is no longer using the reduce() as it was.

It is making certain optimization by considering whether the new state of the corresponding reducer has changed.

If one of the state changes, then it will return the whole new state. Otherwise if none changes ( nextStateForKey !== previousStateForKey keeps returning false ), it will return the previous state, and I assume there won't be any re-rendering.

Redux does this to ensure efficiency. Why re-renders if the state is equivalent as it was.

Due it's deterministic behavior, it will outputs the same result with the same input.

This leads to the question...

Why Pure Function?

As you saw in the preceding code, the combination() determines whether returning a new state is necessary through === operator, which is far efficient than a deep comparison.

Making any mutation to a state (and returning the mutated state) will make the comparison (hasChanged) results to false, which is not something we want to have (because a change HAS occur!).

Now.

One of the characteristic of pure function is it's prohibition to
mutate the arguments the function receives.

It matches exactly on how a reducer needs to be designed!

Every time a changes is made upon a state, a reducer has to return a new fresh state, and NOT making changes to the argument (previous state), therefore making it easier for Redux to tell whether it a change has occur.

It's that simple.