As your JavaScript applications grow, managing all your code in a single file or relying solely on global variables quickly becomes unwieldy. This leads to issues like naming conflicts, difficulty in finding specific logic, and poor reusability. ES6 Modules provide a standardized, robust solution to this problem. They allow you to break down your codebase into smaller, self-contained files, where each file acts as its own module with its own isolated scope. This means variables and functions defined within a module are private by default, preventing global namespace pollution and making your code much easier to manage.
The core of the module system relies on two keywords: export and import. The export keyword is used to make specific functions, variables, classes, or objects from a module available for use in other modules. You can have multiple "named exports" within a single file, like export const PI = 3.14; or export function sum(a, b) { ... }. Additionally, each module can have one "default export", which is often used for the primary entity the module provides, such as export default class Calculator { ... }. Choosing between named and default exports depends on whether you're exporting multiple distinct items or one main item.
Once something is exported from a module, you use the import keyword in another file to bring that functionality into scope. For named exports, you import them using their exact names, for example, import { PI, sum } from './math.js';. For a default export, you can give it any local name you prefer: import MyCalculator from './calculator.js';. This explicit system fosters better code organization, promotes reusability by allowing you to easily share logic across different parts of your application, and significantly improves maintainability. Modern build tools also leverage modules for optimizations like "tree shaking," where unused code is automatically removed, resulting in smaller bundle sizes for production.
Key Takeaways
- Modules prevent global scope pollution by giving each file its own isolated scope.
exportmakes variables, functions, or classes available from a module.importbrings exported items into another module for use.- Use named exports for multiple items, and a default export for the primary item of a module.
- Modules enhance code organization, reusability, and maintainability for large applications.
Code Example
How this code works
The provided code demonstrates how to organize JavaScript applications using modules, allowing code to be shared and reused across different files. utils.js acts as a utility library, defining and exporting useful constants, functions, and classes. app.js then imports and utilizes these components, showcasing the core principle of code organization. This modular approach helps keep projects clean, prevent naming conflicts, and improve maintainability by breaking down large codebases into smaller, manageable pieces.
In utils.js, export const PI and export function add are examples of "named exports." They are given specific names that must be used when importing them. The export default class Greeter makes the Greeter class the primary export from this file; a module can only have one default export. In app.js, import { PI, add } from './utils.js'; brings in the named exports using their exact names within curly braces. Crucially, import MyGreeter from './utils.js'; imports the default export, and here's the subtle part for beginners: MyGreeter is an alias. The Greeter class from utils.js is imported and immediately given the new local name MyGreeter in app.js, which doesn't have to match its original exported name.