聊聊 js 模块化(CommonJS, AMD, CMD, ES6)
前言
文中笔者将介绍几种 js 模块化的规范,以及它们各自的优缺点和差异......
1. CommonJS 规范
CommonJS 主要用在 node 开发上,每个文件就是一个模块,每个文件都有自己的一个作用域。通过module.exports 暴露 public 成员。
此外,CommonJS 通过 require 引入模块依赖,require 函数可以引入 node 的内置模块、自定义模块和 npm 等第三方模块。
var math = require('math');
math.add(2, 3);
优点:
-
简单并容易使用
-
服务器端模块便于重用
缺点:
-
同步的模块加载方式不适合在浏览器环境中
-
不能非阻塞的并行加载多个模块
2. AMD 规范
AMD 是 (Asynchronous Module Definition) 的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
AMD 也采用 require() 语句加载模块,但是不同于 CommonJS,它要求两个参数:
require([module], callback);
第一个参数 module,是一个数组,里面的成员就是要加载的模块;第二个参数 callback,则是加载成功之后的回调函数。如果将前面的 CommonJS 改写成 AMD 形式,就是下面这样:
require(['math'], function (math) {
math.add(2, 3);
});
优点:
-
适合在浏览器环境中异步加载模块
-
可以并行加载多个模块
缺点:
-
提高了开发成本
-
不符合通用的模块化思维方式
3. CMD 规范
CMD 是 (Common Module Definition) 公共模块定义 的缩写。CMD 可能是在 CommonJS 之后抽象出来的一套模块化语法定义和使用的标准。
在 CMD 规范中,一个模块就是一个文件。
示例:
define(function (require, exports, module) {
var clock = require("clock");
clock.start();
});
优点:可以很容易在 node 中运行
缺点:依赖 SPM 打包,模块的加载逻辑偏重
4. ES6 模块化
ES6 模块的设计思想是尽量的 静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。
在 ES6 中,我们使用 export 关键字来导出模块,使用 import 关键字来引入模块。
示例:
// ES6模块
import { stat, exists, readFile } from 'fs';
上面代码实质是从 fs 模块中加载 3 个方法,其他方法不加载。这种加载称为 “编译时加载” 或者 静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。当然,这也导致了没法引用 ES6 模块本身,因为它不是对象。
var firstName = 'Zhou';
var lastName = 'ShuYi';
var year = 1994;
export { firstName, lastName, year };
上面代码在 export 后面,使用大括号指定所要输出的一组变量。export 除了输出变量,还可以输出函数或类。
优点:容易进行静态分析
缺点:原生浏览器端还没有实现该标准
AMD 和 CMD 的区别
对于依赖的模块,
AMD是 提前执行,CMD是 延迟执行。
AMD推崇 依赖前置,CMD推崇 依赖就近。
AMD的 API 默认是一个当多个用,CMD的 API 严格区分,推崇职责单一。
ES6 模块与 CommonJS 模块的差异
CommonJS模块输出的是一个 值的拷贝,ES6模块输出的是 值的引用。
CommonJS模块是运行时加载,ES6模块是编译时输出接口。
CommonJS模块的require()是 同步加载 模块,ES6模块的import命令是 异步加载,有一个独立的模块依赖的解析阶段。
最后
以上就是笔者对于 js 模块化的一些理解,如有不足欢迎大家在评论区指出......
转载自:https://juejin.cn/post/7203968787325960229