模块化规范
JavaScript 的模块化规范经历了多年的发展,旨在帮助开发者更好地组织代码,避免全局命名空间的污染,以及实现代码的复用和维护。以下是一些主要的模块化规范及其特点:

模块化规范发展
CommonJS (CJS)
- 出现时间:2009 年左右
- 适用环境:主要用于,如 Node.js 环境
- 加载方式:同步加载
- 模块定义:使用
module.exports或exports来导出模块的接口,使用require来加载模块。 - 文件扩展名:通常不需要在
require语句中指定文件扩展名,Node.js 会尝试加载.js、.json和.node等文件。
AMD (Asynchronous Module Definition)
- 出现时间:2011 年左右
- 设计哲学:AMD 规范是为了解决异步加载模块的需求,它允许模块在需要的时候,而不是一次性加载所有模块。
- 适用环境:主要用于,解决异步加载问题
- 加载方式:异步加载
- 模块定义:使用
define函数定义模块,使用require函数加载模块。AMD 规范推荐使用异步加载,以提高加载速度和用户体验。 - 文件扩展名:需要在
require语句中指定文件扩展名。
UMD (Universal Module Definition)
- 出现时间:介于 CommonJS 和 AMD 之间
- 设计哲学:UMD 规范是为了兼容多种模块化环境而设计的,它能适应 CommonJS、AMD 和无模块化(即全局变量)的环境。
- 适用环境:可以在 CommonJS、AMD 和全局变量环境下运行
- 加载方式:既可以同步加载也可以异步加载,取决于加载环境
- 模块定义:UMD 模块定义了一种混合模式,可以适应不同的模块加载环境。它通常会检测
define是否存在(AMD),或者module.exports是否存在(CommonJS),并在最后提供一个全局变量的回退方案。
CMD (Common Module Definition)
- 出现时间:2011 年左右发布 SeaJS 后
- 设计哲学:CMD 规范同样支持异步加载,但它更注重,确保依赖模块在当前模块执行前加载完成。
- 适用环境:主要用于,适合于大型 Web 应用,尤其是那些需要动态加载和按需加载资源的场景,如单页应用(SPA)
- 加载方式:CMD 也是异步加载,但更加强调模块间的依赖关系和执行顺序。
- 模块缓存:加载过的模块会被缓存,这意味着如果同一个模块被多次加载,第二次及以后的加载将直接从缓存中读取,避免了重复加载。
- 模块作用域:每个 CMD 模块都有自己的作用域,这避免了全局变量的污染,使得模块之间更加独立,易于维护和扩展。
- 出现时间:随 ES2015(ES6)标准引入
- 适用环境:现代(从 v12 开始默认支持)
- 加载方式:异步加载,使用
import和export语法 - 模块定义:使用
export语句导出模块接口,使用import语句导入模块。ES 模块在设计上考虑了静态分析,这使得工具和编辑器可以更好地理解代码结构。 - 文件扩展名:通常需要指定
.mjs扩展名,但在现代浏览器和最新的 Node.js 版本中,.js文件也可以被识别为 ES 模块,只要在<script>标签中设置了type="module"属性或在 Node.js 中设置相应选项。
总结
随着 ES Modules 在现代 JavaScript 环境中的广泛支持,它已经成为新的标准,被大多数前端框架和库所采用。然而,由于历史遗留和兼容性问题,CommonJS 和 AMD 在一些项目中仍然被使用。对于新的项目,推荐使用 ES Modules,因为它提供了更强大和灵活的模块化解决方案。