CommonJS,AMD模块化规范
模块化开发依然成为前端开发的主流,我们需要做的就是将不同的模块组织起来。最有名的前端模块管理器即requireJS,采用AMD标准。除此之外的其他模块管理器各有特色。
模块化规范
CommonJS
CommonJS**用在服务器端,是服务器模块化的一种规范,NodeJS是其具体实现。加载模块是同步**的。由于NodeJS主要用于服务器的编程,加载的模块文件一般已经存在本地,所以加载起来很快,不用考虑异步加载问题,而前端浏览器需要从服务器加载模块,则必须异步加载,就需要AMD,CDM。
根据CommonJS规范,一个单独文件就是一个模块,加载模块使用require()方法,该方法读取一个文件并执行,最后返回exports对象。
CommonJS定义的模块分为:{模块引用(require)} {模块定义(exports)} {模块标识(module)}
- require()用来引入外部模块;
- exports对象用于导出当前模块的方法或变量,唯一的导出口;
- module对象就代表模块本身,存储了模块的元信息。具体如下:
- module.id——模块的ID。
- module.dependencies——一个数组,存储了此模块依赖的所有模块的ID列表。
- module.exports——与exports指向同一个对象。
AMD/CMD
用在浏览器端,异步加载。
AMD:异步模块定义,是RequireJS在推广过程中对模块定义的规范化产出。先提出的
CMD:通用模块定义,是SeaJS (由玉伯-淘宝前端工程师提出)在推广过程中对模块定义的规范化产出
区别:
1. 对于依赖的模块AMD是提前执行,CMD是延迟执行。不过RequireJS从2.0开始,也改成可以延迟执行(根据写法不同,处理方式不通过)。
2. CMD推崇依赖就近,AMD推崇依赖前置。即SeaJS是懒执行,requireJS是预执行。
- SeaJS只会在真正需要时才执行该模块,严格按照代码中require模块的顺序执行。
- RequireJS中所有依赖的模块加载被提前并行执行了,执行的顺序不能保证。这个问题使用shim参数就可以解决了,shim里面配置好依赖。
官方的解释:SeaJS与RequireJS 的异同
//AMD
define(['./a','./b'], function (a, b) {
//依赖一开始就写好
a.test();
b.test();
});
//CMD
define(function (requie, exports, module) {
//依赖可以就近书写
var a = require('./a');
a.test();
...
//软依赖
if (status) {
var b = requie('./b');
b.test();
}
});
SeaJS和 RequireJS中的define
define(id?, deps?, factory);
事实上SeaJS和RequireJS的define前两个参数的确一样。id都为字符串,都遵循 Module Identifiers。deps都是指依赖模块,类型都为数组。区别仅在于第三个参数factory,虽然类型也都是函数,但factory的参数意义却不同。
RequireJS中factory的参数有两种情况:
1. factory实参和deps数组元素一一对应,数组元素有几个,factory实参个数就有几个。
define(['a', 'b'], function(a, b){
// todo
});
2. 固定为require,exports, module(modules/wrappings格式)。
define(function(require, exports, module){
// todo
});
这种方式是RequireJS后期向 Modules/Wrappings 的妥协,即兼容了它。而SeaJS的define仅支持RequireJS的第二种写法:Modules/Wrappings。
SeaJS和 RequireJS中的require
SeaJS中“依赖”都需要使用require函数去获取,虽然SeaJS的define的第二个参数deps也有“依赖”的意思,但它是提供打包工具(SPM)用的。此外,SeaJS的require是作为参数传入匿名函数内的,RequireJS的require则是全局变量。
三种编写模块的模式
define(function(require, exports, module) {
var a = require('a'); //引入a模块
var b = require('b'); //引入b模块
var data1 = 1; //私有数据
var func1 = function() { //私有方法
return a.run(data1);
}
exports.data2 = 2; //公共数据
exports.func2 = function() { //公共方法
return 'hello';
}
});
或者:
define(function(require) {
var a = require('a'); //引入a模块
var b = require('b'); //引入b模块
var data1 = 1; //私有数据
var func1 = function() { //私有方法
return a.run(data1);
}
return {
data2: 2,
func2: function() {
return 'hello';
}
};
});
如果模块定义没有其它代码,只返回一个对象,还可以有如下简化写法:
define({
data: 1,
func: function() {
return 'hello';
}
})
这种写法适合定义纯JSON数据的模块。
模块化管理器
bower
主要用来进行模块的安装,升级和删除
npm install -g bower
bower install jquery
bower update jquery
bower uninstall jquery
具体内容详见bower一文中。
Grunt
前端开发利器,用来打包管理.js
具体详见grunt+bower 一文中。
browserify
Browserify 是目前最常用的 CommonJS 格式转换的工具。本身也是一个NodeJS模块,可以通过npm来安装。使用类似NodeJS的require的方式来组织浏览器的javascript端代码。
npm install -g browserify
上一篇: 我可以这样理解thinkphp吗
下一篇: shell入门教程(2)