一、ES5 编写模块
模块的核心就是创建独立的作用域,可以通过函数创建作用域
二、CommonJS
CommonJS 规定每个文件就是一个模块,有独立的作用域。每个模块内部,都有一个 module 对象,代表当前模块。通过它来导出 API,它有以下属性:
id 模块的识别符,通常是带有绝对路径的模块文件名;
filename 模块的文件名,带有绝对路径;
loaded 返回一个布尔值,表示模块是否已经完成加载;
parent 返回一个对象,表示调用该模块的模块;
children 返回一个数组,表示该模块要用到的其他模块;
exports 表示模块对外输出的值。
引用模块则需要通过 require 函数,它的基本功能是,读入并执行一个 JavaScript 文件,然后返回该模块的 exports 对象。
特性
- 值拷贝(深拷贝,二者不影响)
- 动态声明 (可以在表达式语句中引用模块)
三、ES6模块规范
- ES6自动采用严格模式
- 引入模块的方式:
<script type='module'></script>
在 Node.js 下使用 ES6 模块则需要将文件名后缀改为“.mjs”,用来和 Node.js 默认使用的 CommonJS 规范模块作区分。
特性
- 值引用 (变量浅拷贝)
- 静态声明
ES6 模块对于引用声明有严格的要求,首先必须在文件的首部,不允许使用变量或表达式,不允许被嵌入到其他语句中。
四、CommonJS VS ES6 modules
五、AMD
Asynchronous Module Definition,异步模块定义
特性
- 异步加载:同时并发加载所依赖的模块,当所有依赖模块都加载完成之后,再执行当前模块的回调函数。
由于 AMD 并不是浏览器原生支持的模块规范,所以需要借助第三方库来实现,其中最有名的就是 RequireJS。
它的核心是两个全局函数 define 和 require,
- define 函数可以将依赖注入队列中,并将回调函数定义成模块;
- require 函数主要作用是创建 script 标签请求对应的模块,然后加载和执行模块。
六、CMD
CMD(Common Module Definition,通用模块定义)是基于浏览器环境制定的模块规范。
定义和引用
CMD 定义模块也是通过一个全局函数 define 来实现的,只有一个参数,该参数既可以是函数也可以是对象:
define(factory);
- 参数是对象,那么模块导出的就是对象;
- 参数为函数,那么这个函数会被传入 3 个参数 require 、 exports 和 module。
define(function(require, exports, module) {
第 1 个参数 require 是一个函数,通过调用它可以引用其他模块,也可以调用 require.async 函数来异步调用模块。
第 2 个参数 exports 是一个对象,当定义模块的时候,需要通过向参数 exports 添加属性来导出模块 API
第 3 个参数 module 是一个对象,它包含 3 个属性:
uri,模块完整的 URI 路径;
dependencies,模块的依赖;
exports,模块需要被导出的 API,作用同第二个参数 exports。
});
特性:懒加载,不需要在定义模块的时候声明依赖,可以在模块执行时动态加载依赖。
CMD 同时支持同步加载模块和异步加载模块,整合了 CommonJS 和 AMD 规范的特点。
遵循 CMD 规范的代表开源项目是 sea.js