Modules (Import/Export)
Modules (Import/Export)
Section titled “Modules (Import/Export)”What it is
Section titled “What it is”ES6 modules provide a standardized way to organize and share code across files. Introduced in ES6 (2015), they allow importing and exporting functions, objects, and values between JavaScript files.
Before this feature
Section titled “Before this feature”Various non-standard solutions existed:
// CommonJS (Node.js)const express = require('express');module.exports = myFunction;
// AMD (RequireJS)define(['dependency'], function(dep) { return myModule;});
// Global variables (browser)window.myLibrary = { /* ... */ };
// IIFEs to avoid global pollution(function() { // private code window.myModule = { /* public API */ };})();After this feature
Section titled “After this feature”Standard, clean module syntax:
// math.js - Named exportsexport const PI = 3.14159;
export function add(a, b) { return a + b;}
export function subtract(a, b) { return a - b;}
// Alternative: export at endfunction multiply(a, b) { return a * b;}function divide(a, b) { return a / b;}export { multiply, divide };
// main.js - Import named exportsimport { add, subtract } from './math.js';import { PI } from './math.js';// or import allimport * as math from './math.js';console.log(math.add(2, 3)); // 5
// user.js - Default export (one per file)export default class User { constructor(name) { this.name = name; }}
// app.js - Import defaultimport User from './user.js';const alice = new User('Alice');
// Mix default and named exportsexport default function main() { /* ... */ }export const VERSION = '1.0.0';export const DEBUG = true;
// Import bothimport main, { VERSION, DEBUG } from './app.js';
// Rename importsimport { add as sum } from './math.js';
// Re-export from another moduleexport { add, subtract } from './math.js';export * from './utils.js';Why this is better
Section titled “Why this is better”- Standard: Same syntax for browser and Node.js (with ESM)
- Explicit: Clear dependencies at top of file
- Tree-shaking: Bundlers can remove unused exports
- Static analysis: Import/export are static, enabling better tooling
- Scoped: Each module has its own scope (no global pollution)
- Async loading: Modules load asynchronously in browsers
Key notes / edge cases
Section titled “Key notes / edge cases”- File extension required in browsers (
.js,.mjs) - Imports are hoisted (executed before other code)
- Imports are read-only bindings (can’t reassign)
- Default export can be unnamed
- Can’t use import/export inside blocks (must be top-level)
- Dynamic imports with
import()for lazy loading
// Dynamic import (ES2020)button.addEventListener('click', async () => { const module = await import('./heavy-feature.js'); module.initialize();});
// Conditional importif (condition) { import('./module-a.js'); // Error! Must be top-level}
// Use dynamic import insteadif (condition) { import('./module-a.js').then(module => { module.doSomething(); });}
// Import is read-onlyimport { count } from './counter.js';count = 10; // TypeError!
// Default export can be expressionexport default function() { /* ... */ }export default class { /* ... */ }export default { key: 'value' };Quick practice
Section titled “Quick practice”-
Export a function
formatDatefrom a fileAnswer
export function formatDate(date) {return date.toISOString();} -
Import
formatDateand use it asformatAnswer
import { formatDate as format } from './utils.js'; -
What’s the difference between default and named exports?
Answer
Default export: one per file, imported without braces. Named exports: multiple per file, imported with braces and exact name (unless renamed).