CommonJS(CMD)模块定义规范

 2015年05月22日    545     声明


CMD(Common Module Definition) 模块定义规范,该规范明确了模块的基本书写格式和基本交互规则,其目的是规范浏览器端JavaScript模块化开发。不仅限于浏览器环境JS,用于服务器端的Node.js也是遵循CMD规范进行模块定义和开发的。

  • 模块应该是单例模式的
  • 模块范围内不应该引入新的自由变量
  • 模块应该按需执行

以上CMD模块定义规范的总则,可以看出CMD推崇模块定义的简单化、独立性及组件化。无论是模块定义时还是模块的调用时,都是应该就近和按需引用,即:在需要时才加载模块,模块的引用越少越少,只加载必需的模块。


1. 模块定义

在CMD规范中,一个模块就是一个文件。模块定义使用define关键字,定义方法如下:

define(factory);
define 是一个全局函数,这个方法接受一个参数,即:要定义的模块factory
  1. factory 可以是一个函数,也可以是一个对象或字符串。
  2. factory 为函数时,表示是模块的构造方法,该方法有三个参数,参数依次是:require、exports 和 module。执行该构造方法,可以得到模块向外提供的接口。
  3. factory 为非函数时,表示模块的接口就是该对象。


2. 模块内容

在模块定义时会传入三个变量,分别是:require、exports 和 module。

define(function(require, exports, module) {

  // 这里是模块的代码

});

2.1 require函数

2.1.1.require是一个方法

  1. require 是一个方法,该方法接收模块标识作为唯一参数,用来获取其他模块提供的接口。
  2. require 会返回导出给外部模块调用的API
  3. 如果要求模块无返回值,require需要返回一个null值。
define(function(require, exports) {

  // 获取模块 a 的接口
  var a = require('./a');

  // 调用模块 a 的方法
  a.doSomething();

});

2.1.2. require.async是一个方法

  1. require.async 是一个方法,该方法接受一个模块标识参数和一个可选的callback(回调)方法参数。
  2. callback方法接收模块的export作为函数参数列表。
  3. 如果要求模块无返回值,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. 模块标识规范

  1. 模块的标识必须是合法的字符串
  2. 模块标识可以不包括文件的扩展名,如:.js
  3. 模块标识可以使用“-”连接,如:foo-bar
  4. 模块标识可以使用相对路径,如:./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');


以上是对CMD规范的一个简单翻译和整理,国内知名的seajsNode.js就是遵循CMD规范的进行模块组织和开发的。