The Module Pattern,模块模式,也译为模组模式,是一种通用的对代码进行模块化组织与定义的方式。这里所说的模块(Modules),是指实现某特定功能的一组方法和代码。许多现代语言都定义了代码的模块化组织方式,好比 Golang 和 Java,它们都使用 package 与 import 来管理与使用模块,而目前版本的 JavaScript 并未提供一种原生的、语言级别的模块化组织模式,而是将模块化的方法交由开发者来实现。所以,出现了不少种 JavaScript 模块化的实现方式,好比,CommonJS Modules、AMD 等。 javascript
一、CommonJS 是一个有志于构建 JavaScript 生态圈的组织。整个社区致力于提升 JavaScript 程序的可移植性和可交换性,不管是在服务端仍是浏览器端。html
a group with a goal of building up the JavaScript ecosystem for web servers, desktop and command line apps and in the browser.前端
一个有目标的构建JavaScript生态系统Web服务器组,在浏览器和命令行应用程序和桌面。(他本身wiki上这么说的)java
这个组织呢制定了一些规范 (能够去他们网站看看 http://www.commonjs.org/)包括CommonJS Modules/1.0 规范,咱们平时所说的commonjs规范,说的就是这个了。node
“The CommonJS API will fill that gap by defining APIs that handle many common application needs, ultimately providing a standard library as rich as those of Python, Ruby and Java. ”--(出自 http://www.commonjs.org/)jquery
因此说Commonjs是一个更偏向于服务器端的规范。Node.js采用了这个规范。 根据CommonJS规范,一个单独的文件就是一个模块。加载模块使用require方法,该方法读 取一个文件并执行,最后返回文件内部的exports对象。git
他又说了,能够用在下面这些场景 ,因此他更明显的偏向服务器端。固然你也能够把它用在浏览器里边(他们本身说能够)。github
二、AMD规范web
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基本都是提早说明依赖模块,而后预加载这些模块,实际上这就要求你提早想好这些依赖,提早写好,否则写代码过程当中要回到开头继续添加依赖。
三、CMD
不知道是否是针对这个问题,淘宝的玉伯大牛搞了个seajs出来,并声称这个规范是遵循CMD规范的,而后给出了这个规范的一个链接(打开会发现draft字样)。关于这个规范呢玉伯在知乎是这么说的
”AMD 是 RequireJS 在推广过程当中对模块定义的规范化产出。
“
因此这个规范其实是为了Seajs的推广而后搞出来的。那么看看SeaJS是怎么回事儿吧,基本就是知道这个规范了。
一样Seajs也是预加载依赖js跟AMD的规范在预加载这一点上是相同的,明显不一样的地方是调用,和声明依赖的地方。AMD和CMD都是用difine和require,可是CMD标准倾向于在使用过程当中提出依赖,就是无论代码写到哪忽然发现须要依赖另外一个模块,那就在当前代码用require引入就能够了,规范会帮你搞定预加载,你随便写就能够了。可是AMD标准让你必须提早在头部依赖参数部分写好(没有写好? 倒回去写好咯)。这就是最明显的区别。
AMD 是 RequireJS 在推广过程当中对模块定义的规范化产出。
CMD 是 SeaJS 在推广过程当中对模块定义的规范化产出。
区别:
1. 对于依赖的模块,AMD 是提早执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改为能够延迟执行(根据写法不一样,处理方式不一样)。CMD 推崇 as lazy as possible.
2. 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服务器端范畴,AMD,CMD客户浏览器端范畴
当咱们写一个文件须要兼容不一样的加载规范的时候怎么办呢,看看下面的代码。
(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 } }));
参考文档
https://my.oschina.net/chenzhiqiang/blog/129783
RequireJS和AMD规范 http://javascript.ruanyifeng.com/tool/requirejs.html
知乎 AMD 和 CMD 的区别有哪些? http://www.zhihu.com/question/20351507