Ch. 1 · JavaScript

JavaScript ES Modules and Live Bindings

JavaScript ES Modules and Live Bindings. Learn the reasoning, a practical example, common mistakes and an interview exercise.

~2 min readintermediateupdated Oct 3, 2026

Imports observe exported bindings rather than copied snapshots. An importer cannot reassign an imported binding; the exporting module owns its updates.

Step-by-step walkthrough

Step 1: Identify the exported owner

An ES module exports bindings that other modules observe. The exporting module controls reassignment of its binding. Distinguish that binding from properties of an exported mutable object, which can have separate mutation permissions.

Step 2: Follow import behavior

An import does not create a reassigned local copy. Observers see changes made through the exporting module’s operations, but cannot assign to the imported binding. This makes a small explicit mutation API more predictable than a writable global variable.

Step 3: Inspect initialization dependencies

Modules evaluate according to their dependency graph. A cycle can expose a binding before it is initialized. Shared helpers should avoid reaching back into partially initialized application modules, and important startup effects should have an explicit owner.

Worked scenario

An exported increment function changes an exported counter, and importers observe the new count.

// counter.js
export let count = 0;
export function increment() { count += 1; }
JavaScript
// app.js
import {count, increment} from './counter.js';
console.log(count); // 0
increment();
console.log(count); // 1
// count = 10; // invalid: imported binding cannot be reassigned
JavaScript

Walk through the example

These are two separate ES module files, not one combined script. Increment changes the exporting module’s variable; the importer observes the updated value through its live binding. A mutable exported object would permit property changes unless another policy restricts them. Module syntax alone does not make objects immutable.

Common mistake

Cycles can expose a binding before initialization. Depending on evaluation order makes module architecture fragile.

Verify the behavior

Run the files under an ES module configuration. Check that reassignment from the importer fails, while the exported increment operation succeeds. If cycles exist, test real initialization order rather than assuming every imported value is already initialized.

Interview exercise

Modify a counter from another module.

Answer and reasoning

Export an operation that owns the change, or expose an immutable result instead of granting arbitrary mutation.

Follow-up discussion

Does importing an object copy it? No: consumers typically share the exported object reference. How do we avoid uncontrolled shared mutation? Expose read functions and domain operations, or export immutable values with clear update ownership instead of a broadly mutable record.

Continue learning

Compare the scenario with the JavaScript interview questions and test your understanding with the JavaScript MCQs. For terminology and implementation details, consult the reference material.

More in JavaScript

read ✓JavaScript · mid

JavaScript Date and Timezone Pitfalls

Parse and format dates without timezone surprises: zero-based months, date-only versus date-time parsing, and why UTC storage avoids drift.

~3 min readread →
read ✓JavaScript · mid

JavaScript Number Precision and BigInt

Why 0.1 + 0.2 is not 0.3, where safe integer range ends, and when BigInt is the right tool for large identifiers and money.

~2 min readread →
esc