liveBook · Manning

Module pattern

As explained in Secrets of the JavaScript Ninja, Second Edition

A design pattern that encapsulates private implementation details behind a public interface, typically by returning an object from a closure or immediate function.

As a JavaScript application grows, scattered global names become harder to manage and more likely to clash with other code. The module pattern groups related behavior behind a small public interface while keeping implementation details out of reach. section 11.0 section 11.1

An immediately invoked function expression (IIFE) creates a private function scope. It returns an object whose methods form the public interface. Those methods close over local variables and functions, keeping them alive after the IIFE finishes without exposing them as object properties. section 11.1.1 section 11.3

Count browser clicks

Create a local click count and handler inside an IIFE, then return an object with a countClicks method that registers the handler with document.addEventListener. Call countClicks through the returned object; the count remains private, but the handler can still update it on later clicks. section 11.1.1

Listing 11.1. The module pattern
const MouseCounterModule = function() {                         #A
  let numClicks = 0;                                            #B
  const handleClick = () => {                                   #C
    alert(++numClicks);                                         #C
  };                                                            #C
  
  return {                                                      #D
    countClicks: () => {                                        #D
      document.addEventListener("click", handleClick);          #D
    }                                                           #D
  };                                                            #D
}();

assert(typeof MouseCounterModule.countClicks === "function",    #E
       "We can access module functionality");                   #E
assert(typeof MouseCounterModule.numClicks === "undefined"      #F
    && typeof MouseCounterModule.handleClick === "undefined" ,  #F
       "We cannot access internal module details");             #F

The click-counter listing shows the whole boundary: local state and handler inside the immediate function, one returned public method outside it. section 11.1.1

A module can be augmented by passing its interface object to another IIFE and adding a method. A scroll-counting extension can keep its own counter private while adding countScrolls. The two functions have separate scopes: extending the interface does not give the extension access to the original module’s private variables. section 11.1.1

Keep the boundary clear:

  • Expose only the operations callers need; leave counters and handlers local. section 11.1 section 11.1.1
  • Use the pattern when working without built-in modules; AMD, CommonJS, and ES6 modules offer other approaches to modular code. section 11.3

How Secrets of the JavaScript Ninja, Second Edition covers it

How deep it goes
Works through IIFE scope, closure-backed private state, a returned interface, and augmentation with separately scoped internals.
Examples
Uses a browser click counter and a scroll-counting extension to show private state, public methods, and augmentation.
What it assumes
Assumes familiarity with JavaScript functions and objects, then applies function scope, immediate functions, and closures to modularization.
What you can do after
Build it from scratch with an IIFE, a returned interface object, and closure-preserved private state.
How it connects
Connects immediate functions, closures, objects, global scope, and browser event handlers; contrasts with AMD, CommonJS, and ES6 modules.

Also explained in

Compare how 2 books explain module pattern →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Secrets of the JavaScript Ninja, Second Edition. The section links point to the parts of the book it draws on.