🔗 一篇搞定CJS,AMD,CMD,ESM
以下是各模块化规范的对比分析,一张表直接理解:
特性 | CommonJS | AMD (RequireJS) | CMD (Sea.js) | ES6 Modules |
---|---|---|---|---|
加载方式 | 同步加载(服务器端) | 异步加载(浏览器端) | 异步加载(浏览器端) | 静态加载(编译时确定依赖) |
语法 | require / module.exports | define / require | define / require | import / export |
依赖声明时机 | 动态依赖(运行时解析) | 依赖前置(提前声明) | 依赖就近(按需声明) | 静态依赖(编译时解析) |
模块执行时机 | 加载时执行 | 提前执行(依赖前置) | 延迟执行(按需执行) | 编译时加载,只执行一次 |
输出类型 | 值的拷贝(原始类型不受影响) | 值的拷贝 | 值的拷贝 | 值的引用(实时绑定) |
循环依赖处理 | 支持但可能导致部分加载 | 支持但需谨慎管理 | 支持但需谨慎管理 | 静态分析支持更好 |
适用环境 | Node.js | 浏览器端 | 浏览器端 | 浏览器 + Node.js(现代环境) |
优缺点 | ✅ 简单易用 ❌ 同步加载不适用浏览器 | ✅ 异步加载优化性能 ❌ 依赖前置不够灵活 | ✅ 依赖就近更灵活 ❌ 社区生态较小 | ✅ 语言标准、静态优化 ❌ 旧环境需转译 |
🔗 详细解释及代码示例
🔗 CommonJS
场景:Node.js 的默认模块系统。
特点:
- 同步加载模块,模块在首次
require
时加载并执行。 - 输出的是值的拷贝(原始类型为拷贝,对象为引用)。
javascript
// math.js
let counter = 0;
const add = () => counter++;
module.exports = { counter, add };
// main.js
const { counter, add } = require('./math');
add();
console.log(counter); // 输出 0(counter 是拷贝值)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
🔗 AMD (Asynchronous Module Definition)
场景:浏览器端异步加载(如 RequireJS)。特点:
- 依赖前置,模块加载后立即执行。
javascript
// 定义模块
define(['dep1', 'dep2'], function(dep1, dep2) {
return { method: () => dep1.doSomething() };
});
// 使用模块
require(['moduleA'], function(moduleA) {
moduleA.method();
});
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
🔗 CMD (Common Module Definition)
场景:浏览器端(如 Sea.js),强调按需加载。特点:
- 依赖就近,模块使用时才加载。
javascript
define(function(require, exports, module) {
const dep1 = require('dep1'); // 按需加载
exports.method = () => dep1.doSomething();
});
1
2
3
4
2
3
4
🔗 ES6 Modules
场景:现代浏览器和 Node.js(需配置)。特点:
- 静态分析,编译时确定依赖。
- 输出值的引用(实时绑定)。
javascript
// math.js
export let counter = 0;
export const add = () => counter++;
// main.js
import { counter, add } from './math.js';
add();
console.log(counter); // 输出 1(counter 是引用)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
🔗 再废话一次,核心区别总结
🔗 加载机制
- CommonJS 同步加载,适合服务器。
- AMD/CMD 异步加载,适合浏览器。
- ES6 静态加载,通用且支持优化。
🔗 模块定义与依赖管理
- CommonJS/AMD/CMD 动态依赖,ES6 静态依赖。
- AMD 依赖前置,CMD 依赖就近,ES6 依赖声明在顶部。
🔗 值的传递
- CommonJS/AMD/CMD 输出值拷贝,ES6 输出实时引用。
🔗 生态与未来
- ES6 是语言标准,支持 Tree-shaking 等优化。
- CommonJS 主导 Node.js 生态,AMD/CMD 逐渐被替代。
🔗 在实际应用中建议大家
- 现代项目:优先使用 ES6 Modules,结合 Webpack/Rollup 打包兼容旧环境。
- Node.js 开发:CommonJS 为主,逐步迁移到 ES6。
- 遗留浏览器项目:AMD 或 CMD 过渡,最终转向 ES6 + 打包工具。