AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
CommonJS 是 服务器端模块的规范,Node.js采用了这个规范
区别:
- 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。
AMD:提前执行(异步加载:依赖先执行)+延迟执行
CMD:延迟执行(运行到需加载,根据顺序执行)
- CMD 推崇依赖就近,AMD 推崇依赖前置。看代码
// CMD
define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
// 此处略去 100 行
var b = require('./b') // 依赖可以就近书写
b.doSomething()
// ...
})
// AMD 默认推荐的是
define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
a.doSomething()
// 此处略去 100 行
b.doSomething()
...
})
虽然 AMD 也支持 CMD 的写法,同时还支持将 require 作为依
赖项传递,但 RequireJS 的作者默认是最喜欢上面的写法,也
是官方文档里默认的模块定义写法。
3.AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。
Commonjs
var i = 1;
var max = 30;
module.exports = function () {
for (i -= 1; i++ < max; ) {
console.log(i);
}
max *= 1.1;
};
module.exports对象,定义了一个函数,该函数就是模块外部与内部通信的桥梁。
加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的module.exports对象。
兼容三者的方案
有人试图实现兼容。也就是自己的代码既能在node上运行,也能在符合amd规范的代码环境中运行。于是产生了umd,其实umd并不算规范,而只能算一种兼容方案,它可以兼容CommonJS和AMD。
兼容amd和cmd
if(typeof define == 'function' && (define.amd != undefined || define.cmd != undefined) {
define(function() {
return fun();
});
}
在requirejs中,一个模块可以如此去定义:
define({});
define(factory);
define(id,dependencies,factor);
define(dependencies,factor)
在seajs中也差不多,但是也有不同之处:
define({});
define(factory);
define(id,dependencies,factory);
define(id,factory);
前面三种都是一样的,但是细节上也有所不同,第一种以对象的方式定义并不能解决我们插件中接口传递的目的,因此不考虑。剩下的就只有两种相同的形式,但是就像前文说到的一样,OMD是为了实现兼容,也就是说它必须作为框架被应用,框架的基础代码具有稳定性,不能让用户改来改去,否则也就失去了规范的意义。而在剩下的两种中,define(id,dependencies,factory)的前两个变量,都需要自己去定义,因此,也被排除。最终也就只有define(factory)这种形式被我们采用。
define(function(){
return {
fun1 : function(a,b) {},
fun2 : function(c,d) {}
}; // return的结果为一个对象
});
兼容comomjs
当define没有被定义的时候,说明跟sea.js和require.js没有任何关系了,这个时候,我们要检查是否支持node.js。
如果是在node.js环境下运行,那么module和exports是一个由核心库提供的全局变量。因此,只需要将插件提供的接口赋值给module.exports,就完成了当前文件(模块)所提供的接口了。
兼容原生的javascript
当以上情况都不满足的情况下,实际上,你所提供的接口,就是一个函数。你提供了一个fun1的接口,你就可以在其他javascript代码中执行fun1()函数。
!!nodejs深入浅出代码
;(function (name, definition) {
// 检测上下文环境是否为AMD或CMD
var hasDefine = typeof define === 'function',
// 检查上下文环境是否为Node
hasExports = typeof module !== 'undefined' && module.exports;
if (hasDefine) {
// AMD环境或CMD环境
define(definition);
} else if (hasExports) {
// 定义为普通Node模块
module.exports = definition();
} else {
// 将模块的执行结果挂在window变量中,在浏览器中this指向window对象
this[name] = definition();
}
})('hello', function () {
var hello = function () {};
return hello;
});