随着前端技术的发展,先后也涌现出了很多模块化技术方案,本人将分享业界js模块化规约
目录
1.1. CommonJS规范
1.2. AMD规范
1.3. CMD规范
1.4. AMD& CMD
1.5. ES6 module
1.1. CommonJS规范
2009年,美国程序员RyanDahl创造了node.js项目,将javascript语言用于服务器端编程。这标志"Javascript模块化编程"正式诞生。老实说,在浏览器环境下,没有模块也不是特别大的问题,毕竟网页程序的复杂性有限;但是在服务器端,一定要有模块,与操作系统和其他应用程序互动,否则根本没法编程。
服务器端的 Node.js 遵循 CommonJS规范,该规范的核心思想是允许模块通过require 方法来同步加载所要依赖的其他模块.
l require 用来引入外部模块
l exports 用于导出当前模块的方法或变量, 对外提供接口
l module module对象代表模块本身
// someModule.js
exports.doSomething=function() {
return"foo";
};
//otherModule.js
var someModule=require('someModule'); // in the vein of node
exports.doSomethingElse=function() {
returnsomeModule.doSomething() +"bar";
};
优点:
- 服务器端模块便于重用
- NPM 中已经有将近20万个可以使用模块包
- 简单并容易使用
缺点:
- 同步的模块加载方式不适合在浏览器环境中(致力于前端),同步意味着阻塞加载,浏览器资源是异步加载的
- 不能非阻塞的并行加载多个模块
实现:
- 服务器端的 Node.js
- Browserify,浏览器端的 CommonJS 实现,可以使用 NPM 的模块,但是编译打包后的文件体积可能很大
- modules-webmake,类似Browserify,还不如 Browserify 灵活wreq,Browserify 的前身
1.2. AMD规范
AsynchronousModule Definition 规范其实只有一个主要函数 define(id?, dependencies?, factory),有一个公有属性 define.amd,它要在声明模块的时候指定所有的依赖 dependencies,并且还要当做形参传到 factory 中,对于依赖的模块提前执行,依赖前置。
优点:
- 适合在浏览器环境中异步加载模块(致力于前端)
- 可以并行加载多个模块
缺点:
- 提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不顺畅
- 不符合通用的模块化思维方式,是一种妥协的实现
实现:
- RequireJS
- curl
在AMD规范中的require函数与一般的 CommonJS中的 require 不同。由于动态检测依赖关系使加载异步,对于基于回调的 require 需求强烈。
define("alpha", ["require", "exports", "beta"], function(require, exports, beta) {
export.verb=function() {
return beta.verb(); // or: return require("beta").verb();
}
});
define(["alpha"], function(alpha) {
return {
verb:function() {
return alpha.verb() +1;
}
}
});
define({
add:function(x, y) {
return x+y;
}
});
1.3. CMD规范
Common ModuleDefinition 规范和 AMD 很相似,尽量保持简单,并与 CommonJS 和 Node.js 的 Modules 规范保持了很大的兼容性,函数有一个公有属性 define.cmd,CMD 模块中有两种方式提供对外的接口,一种是 exports.MyModule = ...,一种是使用 return 进行返回。
define(function(require, exports, module) {
var $=require('jquery');
var Spinning=require('./spinning');
exports.doSomething= ...
module.exports= ...
})
优点:
- 依赖就近,延迟执行
- 可以很容易在Node.js 中运行
缺点:
- 依赖 SPM 打包,模块的加载逻辑偏重
实现:
- Sea.js
- coolie
1.4. AMD& CMD
l CMD和AMD都是CommonJS的一种规范的实现定义,RequireJS和SeaJS是对应的实践;
l 二者都是异步模块定义(AsynchronuousModule Definition)的一个实现;
l CMD和AMD的区别:CMD相当于按需加载,定义一个模块的时候不需要立即制定依赖模块,在需要的时候require就可以了,比较方便;而AMD则相反,定义模块的时候需要制定依赖模块,并以形参的方式引入factory中。
//AMD方式定义模块
define(['dep1','dep2'],function(dep1,dep2){
//内部只能使用制定的模块
return function(){};
});
//CMD
define(function(require,exports,module){
//此处如果需要某XX模块,可以引入
var xx=require('XX');
})
CMD允许异步加载,写法:
require.ensure(["module-a", "module-b"], function(require) {
vara=require("module-a");
// ...
});
Note:require.ensure only loads the modules, it doesn’t evaluate them.
注意:只下载,不执行.
AMD写法,与requireJS一致:
require(["module-a", "module-b"], function(a, b) {
// ...
});
Note:AMD require loads and evaluate the modules. In webpack modules are evaluatedleft to right.
注意:与CMD不一样,AMD会下载并执行,执行顺序从左到右
Note:It’s allowed to omit the callback.
注意:并且允许省略回调
无论是AMD与CMD,文件组织方式与模块之间的逻辑都是一样的
1.5. ES6 module
EcmaScript6 标准增加了JavaScript 语言层面的模块体系定义。ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。
优点:
- 容易进行静态分析
- 面向未来的EcmaScript 标准
缺点:
- 原生浏览器端还没有实现该标准
- 全新的命令字,新版的Node.js才支持
实现:
- Babel