liveBook · Manning

Module

As explained in Secrets of the JavaScript Ninja, Second Edition

A bounded unit of code used to organize and reuse program functionality.

A module is a relatively self-contained cluster of code with a public interface and hidden implementation details. It is larger than a function or object: instead of growing one monolithic program, you group related functionality into smaller, loosely coupled units that are easier to understand, maintain, and reuse. Hiding internals also reduces accidental changes and naming clashes. section 11.0 section 11.1

There are several ways to make that boundary in JavaScript:

  • Before ES6, the module pattern combines an immediately invoked function, which creates a private scope, with closures, which keep its variables available to returned public functions. The returned object serves as the interface. section 11.3
  • AMD defines asynchronously loaded modules and can resolve dependencies automatically; CommonJS uses simpler syntax and synchronous loading, making it more suited to server-side JavaScript. section 11.3
  • ES6 modules are file based. `export` makes selected identifiers available to other modules; `import` brings them in. Unexported identifiers remain inside the module, even when declared at its top level. section 11.2
Listing 11.5. Exporting from a Ninja.js module
const ninja = "Yoshi";                    #A
export const message = "Hello";           #B
                                          #B
export function sayHiToNinja() {          #B
  return message + " " + ninja;           #C
}

Notice the boundary: `message` and `sayHiToNinja` are exported, but `ninja` is not. The exported function can still use `ninja` internally. section 11.2.1

Listing 11.7. Importing from the Ninja.js module
import { message, sayHiToNinja} from "Ninja.js";               #A

assert(message === "Hello",                                    #B
      "We can access the imported variable");                  #B
assert(sayHiToNinja() === "Hello Yoshi",                       #B
      "We can say hi to Yoshi from outside the module");       #B

assert(typeof ninja === "undefined",                           #C
      "But we cannot access Yoshi directly");                  #C

The importing file can call the exported function and read the exported message, but cannot access the unexported `ninja` identifier directly. section 11.2.1

An ES6 module can also have a single default export. Named exports and imports can use aliases when a different name better fits the caller or avoids a clash; `import * as` gathers named exports under one name. Where browsers do not support the module syntax, transpilation with Babel, Traceur, or TypeScript, or loading through SystemJS, is an option. section 11.2.1 section 11.2

Quick check: if an imported module contains a top-level variable but does not export it, can the importing file use that identifier? No—the module’s interface consists of what it explicitly exports. section 11.2 section 11.4

How Secrets of the JavaScript Ninja, Second Edition covers it

How deep it goes
Works from the module pattern through AMD and CommonJS to ES6 export and import forms, with browser-compatibility guidance.
Examples
Uses a greeting module to test exported and private identifiers, plus exercises on valid imports and default exports.
What it assumes
Assumes familiarity with JavaScript functions and objects, then explains why their pre-ES6 scopes need a modularization pattern.
What you can do after
Build it from scratch with the module pattern, or apply ES6 exports and imports to share selected functionality.
How it connects
Connects modules to function scope, closures, immediately invoked functions, AMD, CommonJS, and ES6 imports and exports.

Also explained in

Compare how 35 books explain module →

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.