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; }// app.js
import {count, increment} from './counter.js';
console.log(count); // 0
increment();
console.log(count); // 1
// count = 10; // invalid: imported binding cannot be reassignedWalk 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.