这个问题着重于广度而不是深度,需要对浏览器端和 node 端都有一定的了解,下面就大致介绍一下主流的 JavaScript 模块化实现技术。
目前流行的 JavaScript 模块化技术有:CommonJS, AMD, CMD 以及 ES6
相信大家对 CommonJS 和 ES6 的模块化技术相对比较熟悉,这里就从它们开始,分别简单介绍一下这几个技术吧。
CommonJS
CommonJS 主要是应用于 node 端的模块化技术,实际使用如下:
- 暴露模块
module.exports = xxx
exports.xxx = xxx
- 引入模块
require('path')
需要注意的是:
- 当
exports
和module.exports
同时存在时,module.exports
优先级更高,会直接覆盖exports
- 模块可以被多次加载,但只有第一次加载的时候会被运行,运行之后就将结果缓存起来了,之后再加载都是读取缓存的结果
- 加载模块的方式为同步
ES6
ES6 的模块化是从语言层面实现的模块功能,虽然其旨在成为浏览器和服务器通用的模块化解决方案,但实际上目前还是主要用于浏览器端。实际使用如下:
- 暴露模块
export
export default
- 引入模块
import
需要注意的是:
import
会被 JS 解析引擎静态分析,在编译时就引入模块代码,而不是在运行时动态加载
AMD
AMD,全称 AsyncChronous Module Definition,即异步加载模块。它是应用于浏览器端模块化开发的规范,由于并不是原生 JS 规范,所以使用 AMD 需要引入 RequireJS。
实际使用如下:
-
暴露模块(其实叫定义模块更合适)
define('moduleName', ['dependA', 'dependB'], function(ma, mb) { /*do someting*/ return exportModule })
-
引入模块
require(['dependA', 'dependB'], function(ma, mb) { /*do someting*/ })
需要注意的是:
- 由于 AMD 是异步加载模块,所以加载并不影响后面的代码执行
CMD
CMD,全称 Common Module Definition,即通用模块定义。它与 AMD 非常相似,但本质上又有不同:
AMD 推崇依赖前置、提前执行,而 CMD 是依赖就近、延迟执行
这是什么意思呢?我们可以看到,上面 AMD 在定义模块是,直接把依赖写在参数中,声明并且初始化了所有依赖的模块,而 CMD 则是下面这样:
define(function(require, exports, module) {
var ma = require('./dependA');
/* do something */
if (false) {
var mb = require('./dependB');
/* do something */
}
});
相信从代码大家就能很明显的看出答案了,CMD 是需要什么依赖的时候再引入什么模块。