浅谈JavaScript模块化规范AMD与CMD

1、模块化

模块化是指在解决某一个复杂问题或者一系列的杂糅问题时,依照一种分类的思维把问题进行系统性的分解以之处理。模块化是一种处理复杂系统分解为代码结构更合理,可维护性更高的可管理的模块的方式。模块化使得系统被分解为一组高内聚,低耦合的模块,在理想状态下只需要完成自己部分的核心业务逻辑代码,其他方面的依赖可以通过直接加载被人已经写好模块进行使用即可。

一个模块化系统所必须的能力:

1) 定义封装的模块。

2) 定义新模块对其他模块的依赖。

3) 可对其他模块的引入支持。

 

2、模块化的规范

为了 JavaScript 的模块化开发,特别是在浏览器端的模块化开发,实现了几种规范:

1) AMD,异步模块定义,是 RequireJS 在推广过程中对模块定义的规范化产出。

2) CMD,通用模块定义,是 SeaJS 在推广过程中对模块定义的规范化产出。

3) CommonJS,是 BravoJS 在推广过程中对模块定义的规范化产出。

 

3、AMD与RequireJS:

所有的模块将被异步加载,模块加载不影响后面语句运行。所有依赖某些模块的语句均放置在回调函数中。

AMD规范定义了一个自由变量或者说是全局变量 define 的函数。

语法:define([id], [dependencies], factory);    

1) id:字符串类型,表示模块标识,为可选参数。若不存在则模块标识应该默认定义为在加载器中被请求脚本的标识。如果存在,那么模块标识必须为顶层的或者一个绝对的标识。

2) dependencies:一个当前模块依赖的,已被模块定义的模块标识的数组字面量。

3) factory:一个需要进行实例化的函数或一个对象,无依赖模块可以直接使用对象字面量来定义。

RequireJS 是一个前端的模块化管理的工具库,遵循AMD规范。

RequireJS 的基本思想为:通过一个函数来将所有所需要的或者说所依赖的模块实现装载进来,然后返回一个新的函数(模块),所有的关于新模块的业务代码都在这个函数内部操作,其内部也可无限制的使用已经加载进来的模块。

defined用于定义模块,RequireJS要求每个模块均放在独立的文件之中。按照是否有依赖其他模块的情况分为独立模块和非独立模块。

1) 独立模块,不依赖其他模块,直接定义:

define({

method1: function() {},

method2: function() {}

});

等价于

define(function() {

return {

  method1: function() {},

  method2: function() {}

}

});

2) 非独立模块,对其他模块有依赖:

define([‘module1’, ‘module2’], function(m1, m2) {

});

等价于

define(function(require) {

var m1 = require(‘module1’),

var m2 = require(‘module2’);

});
4、CMD与SeaJS:

在CMD中,一个模块就是一个文件,格式为:define( factory );

全局函数define,用来定义模块。

参数 factory可以是一个函数,也可以为对象或者字符串,当 factory 为对象、字符串时,表示模块的接口就是该对象、字符串。

1)  定义JSON数据模块:

define({ “foo”: “bar” });

2) 通过字符串定义模板模块:

define(‘this is {{data}}.’);

3) factory 为函数的时候,表示模块的构造方法,执行构造方法便可以得到模块向外提供的接口:

define(function(require, exports, module) { 

    …

});

语法:define([id], [deps], factory);

字符串id为模块标识(可选),数组deps为模块依赖(可选),factory有三个参数,一是require, 二是export,三是modules。

1) require

① require( id ):接受模块标识作为唯一的参数,用来获取其他模块提供的接口。

define(function(require, exports) {

var a = require(‘./a’);

a.funA();

});

② require.async( id, [callback]):require是同步往下执行的,需要的异步加载模块可以使用 require.async 来进行加载。

define(function(require, exports, module) { 

require.async(‘.a’, function(a) {

a.funA();

});

});

③ require.resolve( id ):可以使用模块内部的路径机制来返回模块路径,不会加载模块。

2) export

export用来向外提供模块接口。

define(function(require, exports) {

    exports.foo = ‘bar’; // 向外提供的属性

    exports.do = function(){}; // 向外提供的方法

});

当然也可以使用 return 直接向外提供接口。

define(function(require, exports) {

    return{

        foo : ‘bar’, // 向外提供的属性

        do : function(){} // 向外提供的方法

    }

});

也可以简化为直接对象字面量的形式。

define({

    foo : ‘bar’, // 向外提供的属性

    do : function(){} // 向外提供的方法

});

3) module

module为一个对象,存储了一些与当前模块相关联的属性与方法:

① module.id 为模块的唯一标识。

② module.uri 根据模块系统的路径解析规则得到模块的绝对路径。

③ module.dependencies 表示模块的依赖。

④ module.exports 当前模块对外提供的接口。

SeaJS:

核心特征:

1) 遵循CMD规范,与NodeJS般的书写模块代码。

2) 依赖自动加载,配置清晰简洁。

seajs.use :用来在页面中加载一个或者多个模块。

// 加载一个模块 

seajs.use(‘./a’);

// 加载模块,加载完成时执行回调

seajs.use(‘./a’, function(a) {

    a.funA();

});

// 加载多个模块执行回调

seajs.use([‘./a’,’./b’], function(a , b) {

    a.funA();

    b.funB();

});

其define 与 require 使用方式基本就是CMD规范中的示例。

 

5、AMD与CMD的区别

1) 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。但RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。

2) AMD 推崇依赖前置;CMD 推崇依赖就近。

AMD:

define([‘./a’, ‘./b’], function(a, b) { // 依赖必须一开始就写好

a.funA();

b.funB();

})

CMD:

define(function(require, exports, module) {

// 依赖可以就近书写

var a = require(‘./a’);

a.funA();

var b = require(‘./b’)

b.funB();

… 

})

欢迎分享本文,转载请保留出处:前端ABC » 浅谈JavaScript模块化规范AMD与CMD

分享到:更多 ()

发表评论 0