CMD(Common Module Definition) 模块定义规范,该规范明确了模块的基本书写格式和基本交互规则,其目的是规范浏览器端JavaScript模块化开发。不仅限于浏览器环境JS,用于服务器端的Node.js也是遵循CMD规范进行模块定义和开发的。
- 模块应该是单例模式的
- 模块范围内不应该引入新的自由变量
- 模块应该按需执行
以上CMD模块定义规范的总则,可以看出CMD推崇模块定义的简单化、独立性及组件化。无论是模块定义时还是模块的调用时,都是应该就近和按需引用,即:在需要时才加载模块,模块的引用越少越少,只加载必需的模块。
1. 模块定义
在CMD规范中,一个模块就是一个文件。模块定义使用define
关键字,定义方法如下:
define(factory);
define
是一个全局函数,这个方法接受一个参数,即:要定义的模块factory-
factory
可以是一个函数,也可以是一个对象或字符串。 -
factory
为函数时,表示是模块的构造方法,该方法有三个参数,参数依次是:require、exports 和 module。执行该构造方法,可以得到模块向外提供的接口。 -
factory
为非函数时,表示模块的接口就是该对象。
2. 模块内容
在模块定义时会传入三个变量,分别是:require、exports 和 module。
define(function(require, exports, module) { // 这里是模块的代码 });
2.1 require
函数
2.1.1.require
是一个方法
-
require
是一个方法,该方法接收模块标识
作为唯一参数,用来获取其他模块提供的接口。 -
require
会返回导出给外部模块调用的API
。 -
如果要求模块无返回值,
require
需要返回一个null
值。
define(function(require, exports) { // 获取模块 a 的接口 var a = require('./a'); // 调用模块 a 的方法 a.doSomething(); });
2.1.2. require.async
是一个方法
-
require.async
是一个方法,该方法接受一个模块标识
参数和一个可选的callback(回调)方法
参数。 -
callback方法
接收模块的export作为函数参数列表。 -
如果要求模块无返回值,
requested
需要接收一个null
值。
define(function(require, exports, module) { // 异步加载一个模块,在加载完成时,执行回调 require.async('./b', function(b) { b.doSomething(); }); // 异步加载多个模块,在加载完成时,执行回调 require.async(['./c', './d'], function(c, d) { c.doSomething(); d.doSomething(); }); });
2.2 exports
对象
在模块中,exports
是一个对象,用来向外提供模块接口。模块向外提供的API
会被添加到exports
对象中。
define(function(require, exports) { // 对外提供 foo 属性 exports.foo = 'bar'; // 对外提供 doSomething 方法 exports.doSomething = function() {}; });
2.3 module
对象
2.2.1.module.uri
根据模块系统的路径解析规则得到的模块绝对路径。
2.2.2.module.dependencies
dependencies 是一个数组,表示当前模块的依赖列表。
2.2.3.module.exports
exports是一个对象,当前模块对外提供的接口。
3. 模块标识规范
- 模块的标识必须是合法的字符串
-
模块标识可以不包括文件的扩展名,如:
.js
-
模块标识可以使用“-”连接,如:
foo-bar
-
模块标识可以使用相对路径,如:
./foo
、../bar
4. 示例代码
一个典型的示例:
math.js
define(function(require, exports, module) { exports.add = function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) { sum += args[i++]; } return sum; }; });
increment.js
define(function(require, exports, module) { var add = require('math').add; exports.increment = function(val) { return add(val, 1); }; });
program.js
define(function(require, exports, module) { var inc = require('increment').increment; var a = 1; inc(a); // 2 module.id == "program"; });
非函数参数(factory参数)模块定义
object-data.js
define({ foo: "bar" });
array-data.js
define([ 'foo', 'bar' ]);
string-data.js
define('foo bar');