ES Modules: import and export Syntax
Modern JavaScript applications are built from many small, interconnected files, each serving a specific purpose. ES Modules (ECMAScript Modules), introduced formally in ES2015, are the official, standardized way to create modular and reusable JavaScript code. They provide a robust system for encapsulating code, managing dependencies, and preventing global scope pollution.
At the heart of ES Modules are two primary keywords: export and import.
1. The export Keyword: Making Code Available
The export keyword is used to make variables, functions, classes, or objects available for other JavaScript files (modules) to use. Anything declared within a module is private by default unless explicitly exported.
Syntax for Named Exports:
You can export multiple individual items from a single module. These are called named exports. When importing them, you must use the exact same name.
// --- file: mathOperations.js ---
// Exporting variables
export const PI = 3.14159;
export const E = 2.71828;
// Exporting functions
export function add(a, b) {
return a + b;
}
export const subtract = (a, b) => {
return a - b;
};
// Exporting classes
export class Calculator {
constructor() {
this.history = [];
}
add(a, b) {
const result = a + b;
this.history.push(`${a} + ${b} = ${result}`);
return result;
}
}
// You can also export a list of already declared items
const multiply = (a, b) => a * b;
const divide = (a, b) => a / b;
export { multiply, divide };
// Note: 'private' variable - not exported
const SECRET_KEY = 'super_secret';
In mathOperations.js, PI, E, add, subtract, Calculator, multiply, and divide are all named exports. SECRET_KEY remains private to mathOperations.js.
2. The import Keyword: Using Exported Code
The import keyword is used in a JavaScript file to bring in exports from another module. When you import, you're creating a "live binding" to the exported value. This means if the original module changes the value of an exported variable, the imported value will reflect that change.
Syntax for Named Imports:
To import named exports, you use curly braces {} around the names you want to import, matching their exact export names.
// --- file: main.js ---
// Assuming mathOperations.js is in the same directory
// Import specific named exports
import { add, PI } from './mathOperations.js';
// Import all named exports as a single object
import * as math from './mathOperations.js';
console.log('--- ES Modules Import/Export Demo ---');
console.log('');
// Using imported 'add' function and 'PI' constant
console.log('Using specific imports:');
console.log(' PI is: ' + PI);
console.log(' 2 + 3 = ' + add(2, 3)); // Calls the imported add function
console.log('');
// Using imports from the 'math' object (all exports)
console.log('Using namespace import (* as math):');
console.log(' E is: ' + math.E);
console.log(' 10 - 4 = ' + math.subtract(10, 4));
console.log(' 4 * 5 = ' + math.multiply(4, 5));
const myCalculator = new math.Calculator();
console.log(' Calculator add: 7 + 8 = ' + myCalculator.add(7, 8));
console.log(' Calculator history: ' + JSON.stringify(myCalculator.history));
// Attempting to access a non-exported item will fail
// console.log(math.SECRET_KEY); // This would cause an error!
Output of main.js (when run in a module-enabled environment):
--- ES Modules Import/Export Demo ---
Using specific imports:
PI is: 3.14159
2 + 3 = 5
Using namespace import (* as math):
E is: 2.71828
10 - 4 = 6
4 * 5 = 20
Calculator add: 7 + 8 = 15
Calculator history: ["7 + 8 = 15"]
3. Key Characteristics of ES Modules
ES Modules bring several fundamental changes to how JavaScript code is loaded and executed, compared to traditional scripts:
- Strict Mode by Default: All code inside an ES Module runs in strict mode, even without the
"use strict"directive. This means common JavaScript "mistakes" (like assigning to an undeclared variable) will become errors. - Module Scope: Variables and functions declared in the top-level of a module are scoped to that module, not to the global
windowobject (in browsers) orglobalobject (in Node.js). They are private unless explicitlyexported. - Single Evaluation: Each module is evaluated only once, regardless of how many times it's imported. Subsequent imports of the same module will receive the same instance, ensuring state consistency.
- Asynchronous Loading: Modules are loaded asynchronously, which means they don't block the main thread of execution.
- Static Structure: Imports and exports are resolved at compile time (or parse time in browsers), not at runtime. This allows for better tooling (like static analysis, tree-shaking by bundlers).
thisContext: Thethiskeyword at the top-level of a module isundefined, unlike in traditional scripts where it refers to the global object.- File Extension and MIME Type:
- In browsers, you must use
<script type="module" src="main.js"></script>. The browser then expectsmain.jsand any modules it imports to adhere to module syntax. - In Node.js, you can use the
.mjsfile extension (e.g.,main.mjs) or specify"type": "module"in yourpackage.jsonfile for your.jsfiles.
- In browsers, you must use
ES Modules provide a powerful and standardized way to build scalable and maintainable JavaScript applications by enabling clear dependency management and code organization.

