这是一篇关于javascript模块化AMD,CMD,CommonJS的学习总结,做为记录也给一样对三种方式有疑问的童鞋们,有不对或者误差之处,望各位大神指出,不胜感激。javascript
本篇默认读者大概知道require,seajs的用法(AMD,CMD用法),因此没有加入使用语法。html
一、为什么而生:java
这三个规范都是为javascript模块化加载而生的,都是在用到或者预计要用到某些模块时候加载该模块,使得大量的系统巨大的庞杂的代码得以很好的组织和管理。模块化使得咱们在使用和管理代码的时候不那么混乱,并且也方便了多人的合做。jquery
二、那些规范们:git
(1)、CommonJS 是一个有志于构建 JavaScript 生态圈的组织。整个社区致力于提升 JavaScript 程序的可移植性和可交换性,不管是在服务端仍是浏览器端。es6
a groupwith a goal of building up the JavaScript ecosystem for web servers, desktopand command line apps and in the browser.github
一个有目标的构建JavaScript生态系统Web服务器组,在浏览器和命令行应用程序和桌面。(他本身wiki上这么说的)web
这个组织呢制定了一些规范 (能够去他们网站看看 http://www.commonjs.org/)包括CommonJS Modules/1.0 规范,咱们平时所说的commonjs规范,说的就是这个了。api
“TheCommonJS API will fill that gap by defining APIs that handle many commonapplication needs, ultimately providing a standard library as rich as those ofPython, Ruby and Java. ”--(出自 http://www.commonjs.org/)跨域
因此说Commonjs是一个更偏向于服务器端的规范。Node.js采用了这个规范。 根据CommonJS规范,一个单独的文件就是一个模块。加载模块使用require方法,该方法读 取一个文件并执行,最后返回文件内部的exports对象。
他又说了,能够用在下面这些场景 ,因此他更明显的偏向服务器端。固然你也能够把它用在浏览器里边(他们本身说能够)。
· Server-side JavaScript applications
· Command line tools
· Desktop GUI-based applications
· Hybrid applications (Titanium, Adobe AIR)
(2)、AMD规范
Commonjs解决了模块化的问题,而且能够用在浏览器中,可是Commonjs是同步加载模块,当要用到该模块了,现加载现用,这种同步机制到了浏览器里边就有问题了,加载速度啊啥的(览器同步加载模块会致使性能、可用性、调试和跨域访问等问题)。
鉴于浏览器的特殊状况,又出现了一个规范,这个规范呢能够实现异步加载依赖模块,而且会提早加载那就是AMD规范。AMD能够做为CommonJS模块一个中转的版本只要CommonJS没有被用来同步的require调用。使用同步require调用的CommonJS代码能够被转换为使用回调风格的AMD模块加载器(https://github.com/amdjs/amdjs-api/wiki/AMD-(%E4%B8%AD%E6%96%87%E7%89%88) (它说的)。
下面是一个使用了简单CommonJS转换的模块定义(它是amd规范的一种用法):
define(function (require, exports, module) {
var a = require('a'),
b = require('b');
exports.action = function () {};
});
因此说AMD和Commonjs是兼容的,只要稍稍调换一下调用方法就实现了同步加载(我很怀疑amd也是在commonjs基础上加了个壳,而后并无找到其余的神马说明和支持的文字,找到了必定加到这)。
看一下AMD规范你会发现,AMD基本都是提早说明依赖模块,而后预加载这些模块,实际上这就要求你提早想好这些依赖,提早写好,否则写代码过程当中要回到开头继续添加依赖。
(3)、CMD
不知道是否是针对这个问题,淘宝的玉伯大牛搞了个seajs出来,并声称这个规范是遵循CMD规范的,而后给出了这个规范的一个链接(打开会发现draft字样)。关于这个规范呢玉伯在知乎是这么说的
”AMD 是 RequireJS 在推广过程当中对模块定义的规范化产出。
CMD 是 SeaJS 在推广过程当中对模块定义的规范化产出。
相似的还有 CommonJSModules/2.0 规范,是 BravoJS 在推广过程当中对模块定义的规范化产出。
还有很多⋯⋯
“
因此这个规范其实是为了Seajs的推广而后搞出来的。那么看看SeaJS是怎么回事儿吧,基本就是知道这个规范了。
一样Seajs也是预加载依赖js跟AMD的规范在预加载这一点上是相同的,明显不一样的地方是调用,和声明依赖的地方。AMD和CMD都是用difine和require,可是CMD标准倾向于在使用过程当中提出依赖,就是无论代码写到哪忽然发现须要依赖另外一个模块,那就在当前代码用require引入就能够了,规范会帮你搞定预加载,你随便写就能够了。可是AMD标准让你必须提早在头部依赖参数部分写好(没有写好? 倒回去写好咯)。这就是最明显的区别。
三、共生共处
因为CommonJS是服务器端的规范,更另外两个标准实际不冲突。
AMD在国外用的更多,固然国内也是很多的,jQuery1,7版本开始使用,Dojo在1.6版本开始用,这已经可以证实它足够牛x了。
CMD固然也有不少人在用,可是基本都集中在国内,Seajs官网就展现了一大堆牛逼的公司在用(包括爱奇艺,腾讯微博,支付宝,淘宝等一大堆,去这看看http://seajs.org/docs/),估计小的不出名的也不可胜数了,毕竟不少公司招聘都要求会seajs嘛。
因此三个规范目前都挺好(其实也主要是由于js么有本身的模块加载机制,es6出来以后不知道会怎样)。
当咱们写一个文件须要兼容不一样的加载规范的时候怎么办呢,看看下面的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery', 'underscore'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS之类的
module.exports = factory(require('jquery'), require('underscore'));
} else {
// 浏览器全局变量(root 即 window)
root.returnExports = factory(root.jQuery, root._);
}
}(this, function ($, _) {
// 方法
function a(){}; // 私有方法,由于它没被返回 (见下面)
function b(){}; // 公共方法,由于被返回了
function c(){}; // 公共方法,由于被返回了
// 暴露公共方法
return {
b: b,
c: c
}
})); |
这个代码能够兼容各类加载规范了。
四、AMD和CMD的区别
下面这几点是玉伯在知乎上说的。
1. 对于依赖的模块,AMD 是提早执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改为能够延迟执行(根据写法不一样,处理方式不一样)。CMD 推崇 as lazy aspossible.
2. CMD 推崇依赖就近,AMD 推崇依赖前置。
3. AMD 的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。好比 AMD 里,require 分全局 require 和局部 require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每一个 API 都简单纯粹。
4. 还有一些细节差别,具体看这个规范的定义就好,就很少说了。
( 好吧~第四点是很少说了。。。。。。。。。)
五、AMD和CMD的一些相同
都有difine和require,并且调用方式实际均可以添加依赖参数,也就是说均可以用提供依赖参数的方式来实现预加载依赖模块(可是不推荐由于 注意:带 id 和 deps 参数的 define 用法不属于 CMD 规范,而属于 Modules/Transport 规范。---来自:https://github.com/seajs/seajs/issues/242)。
AMD也能够在factory中使用require来现加载用到的模块,可是这个模块就不会预先加载,属于用到才加载的同步加载了。
var a = require('a'); //加载模块a