What are JavaScript modules (import/export)?
Modules let you split code into separate files that share functionality through import and export. Each module has its own scope.
Named exports — export multiple values by name; import them with matching names in braces.
Default export — one main export per file, imported with any name.
Benefits — encapsulation, reusability, and clearer dependencies.
Modern ES Modules load asynchronously and support tree shaking, so bundlers can drop unused exports.
// math.js — Named exports
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export function multiply(a, b) { return a * b; }
// user.js — Default export
export default class User {
constructor(name) { this.name = name; }
}
// app.js — Importing
import User from './user.js'; // Default (any name)
import { add, PI } from './math.js'; // Named (exact names)
import { multiply as mul } from './math.js'; // Rename
import * as math from './math.js'; // Namespace import
// Re-export
export { add, multiply } from './math.js';
export { default as User } from './user.js';
// Dynamic import (code splitting)
const module = await import('./heavy-module.js');
module.doSomething();
// In HTML
// <script type="module" src="app.js"></script>Named exports: imported with { } using exact names. Default export: imported without { } using any name. * as namespace imports everything.
Dynamic import() loads modules on demand (code splitting). Re-exports create barrel files (index.js that re-exports from sub-modules). type='module' enables ESM in browsers.
Know named vs default exports: named = { }, default = no { }. Dynamic import() for code splitting.
ESM vs CommonJS (static vs dynamic). Tree shaking only works with named exports (bundlers can analyze static imports). type='module' in HTML.