当我写这篇文章的时候,sea.js已经逐渐退出历史的舞台,详细链接。不过任何新事物的出现都是对旧事物的取其精华,去其糟粕,所以了解一下以前模块的加载也是一件好事。
js模块化的原因自不比多说,看看HUX同学的js模块加载七日谈就知道了,将的非常详细。
一 .CMD模块加载规范
一个js文件就是一个模块,定义如下:define(factory);
factory可以使一个函数,一个对象,或者一个字符串。
1.factory是一个函数
define(function(require,exports,module){
var a = reuire('./a');//执行到此处时模块a同步下载并且执行,这个就是和AMD模式的不同之处
a.dosomething();
exports.foo = function(){};
});
或者
define(function(require,exports,module){
var a = reuire('./a');//执行到此处时模块a同步下载并且执行,这个就是和AMD模式的不同之处
a.dosomething();
return {
foo:function(){}
}
});
另外,在require方法中还有一个异步加载方式:
require.async('./b',function(b){
b.dosomething();
});
这里b模块异步加载,对于那些不是需要及时调用的模块可以考虑。
2.factory是一个对象,字符串的时候表示该模块的接口就死该对象。
define({
name:'leilie',
say:function(){}
});或者,
define("hello ,llei");
define函数也接受2个以上的参数:
//id是模块标识符,depends是依赖的模块。
define(id,[depends],function(require,exports,module){
//代码
});
然而,这种方式的模块定义并不是CMD规范,而是Modules/Transport 规范,也许你也看出来了,既然有了depends参数,为何factory函数还有require,这就是CMD和
AMD的区别。
sea.js的用法
seajs完全遵守CMD规范,可以在官方链接中找到详细的文档。
二.AMD规范
玉伯大牛有一个链接将的非常好,介绍了模块的发展。
AMD也是利用define函数来加载的,具体定义如下:
define(id,[depends],factory);////id是模块标识符,depends是依赖的模块
模块标识符
第一个参数,id,是个字符串,它指的是定义中模块的名字,这个参数是可选的。如果没有提供该参数,模块的名字应该默认为模块加载器请求的指定脚本的名字。如果提供了 该参数,模块名必须是“*”的和绝对的(不允许相对名字)。
依赖
第二个参数,dependencies,是个定义中模块所依赖模块的数组。依赖模块必须根据模块的工厂方法优先级执行,并且执行的结果应该按照依赖数组中的位置顺序以参数的
依赖的模块名如果是相对的,应该解析为相对定义中模块。换句话来说,相对名解析为相对与模块的名字,并非相对于寻找该模块的名字的路径。
本规范定义了截然不同的三种特殊的依赖关键字。如果"require","exports", 或 "module"出现在依赖列表中,参数应该按照CommonJS模块规范*变量去解析。
依赖参数是可选的,如果忽略此参数,它应该默认为["require", "exports", "module"]。然而,如果工厂方法的长度属性小于3,加载器会选择以函数的长度属性指定的参数个数调用工厂方法。
工厂方法
第三个参数,factory,为模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值。
如果工厂方法返回一个值(对象,函数,或任意强制类型转换为true的值),应该为设置为模块的输出值。
三 二者的不同之处
define(["require"], function(require) {
// 在这里,模块 a 已经下载并执行好 //
var a = require("./a") // 此处仅仅是取模块 a 的 exports,然而,其实你并不想运行a那么这是不合理的
});
针对上面的不合理之处,那么直接使用CMD规范不就好了,然而:
- 不能直接压缩:
require
是局部变量,意味着不能直接的通过压缩工具进行压缩,若require
这个变量被替换,加载器与自动化工具将无法获取模块的依赖。 - 模块书写有额外约定:路径参数不能进行字符串运算,不能使用变量代替,否则加载器与自动化工具无法正确提取路径。