为什么要模块化?
当开发复杂项目时,模块化能解决以下问题:
- 避免变量污染:通过隔离作用域,避免全局变量的干扰。
- 提升代码的维护性:模块化组织代码后,每个模块专注于自身的功能,减少了耦合性。
- 增强代码的可读性:模块化明确了依赖关系,代码结构更加清晰。
- 方便协作开发:开发者可以专注于自己的模块,减少冲突。
模块化的意义是什么?
模块化的核心是 隐藏内部实现 和 暴露外部接口:
- 隐藏实现:封装细节,让模块内部的变量和方法不会泄漏到外部。
- 暴露接口:通过接口提供功能,外部只需关注如何调用,而无需关心实现细节。
模块化规范
1. CommonJS
背景:
CommonJS 是为 Node.js 提供模块化支持而诞生的,它专注于服务端开发,是一种同步加载模块的规范。
导出
-
通过
exports
导出单个属性或方法:exports.add = function (a, b) { return a + b; };
-
通过
module.exports
导出整个对象:module.exports = { add(a, b) { return a + b; }, subtract(a, b) { return a - b; } };
注意:
exports
是module.exports
的引用,不能直接覆盖exports
,否则会导致导出失效。
导入
使用 require
语句导入模块:
const math = require('./math'); // 通过相对路径导入模块
console.log(math.add(1, 2)); // 调用导入的方法
特点
- 模块在首次加载时同步执行并缓存。
- 模块的加载顺序按照引用顺序执行。
2. AMD 和 CMD
背景:
- AMD(Asynchronous Module Definition)和 CMD(Common Module Definition)是为浏览器环境设计的模块化规范,用于解决前端模块依赖管理的问题。
AMD(RequireJS)
-
主要特点是提前加载模块,适合依赖较多的场景。
-
使用
define
定义模块,使用
require
引入模块:
define(['moduleA', 'moduleB'], function (moduleA, moduleB) { const result = moduleA.doSomething() + moduleB.doSomethingElse(); return result; });
CMD(SeaJS)
-
主要特点是按需加载模块,更灵活。
-
使用
define
定义模块,使用
require
按需引入:
define(function (require, exports, module) { const moduleA = require('./moduleA'); const moduleB = require('./moduleB'); exports.result = moduleA.doSomething() + moduleB.doSomethingElse(); });
3. ES 模块化
背景:
ES 模块化(ESM)是 JavaScript 的原生模块化标准,目前是浏览器和 Node.js 主流支持的模块化规范。
导出
-
普通导出:
export const PI = 3.14; export function add(a, b) { return a + b; }
-
默认导出:
export default function subtract(a, b) { return a - b; }
-
批量导出:
const name = 'John'; const age = 30; export { name, age };
-
重命名导出:
const version = '1.0.0'; export { version as appVersion };
-
引用导出:
export { add as sum } from './math.js';
导入
-
普通导入:
import { add, PI } from './math.js'; console.log(add(2, 3));
-
默认导入:
import subtract from './math.js'; console.log(subtract(5, 2));
-
重命名导入:
import { add as sum } from './math.js'; console.log(sum(2, 3));
-
全部导入:
import * as math from './math.js'; console.log(math.add(1, 2));
-
动态导入:
import('./math.js').then(math => { console.log(math.add(2, 3)); });
特点
- 支持静态分析,提升了工具链的优化能力(如 Tree Shaking)。
- 只支持顶层导入和导出,不支持条件导入导出。