exports
首先是 exports 的几种形式,我们可以:
define(function(require, exports, module) {
exports.a = 'a';
exports.fn = function() {};
});
也可以:
define(function(require, exports, module) {
module.exports = {
a: 'a',
fn: function() {}
};
});
这两者有什么区别呢?
- 就最终的效果而言,这两种形式没什么区别:都是使得该模块对外提供 xx 和 fn 两个公共成员。
- 就代码组织形式而言,
exports.xx = ...是分散赋值,中间可以穿插其他代码,很灵活。module.exports = { ... }则是集中式赋值,便于管理。两种形式各有优劣,采用何种方式,很大程度上取决于个人喜好。 - 就内部实现而言,在传入参数时,
exports = module.exports = {}, 很明显,第一种方式复用了{}初始值,第二种则给 module.exports 重新赋了一个新对象。由于require('module-id')返回的是module.exports, 因此最终的效果两种形式是一致的。 - 更直观的一种形式是
exports = { ... }, 但由于 JavaScript 里只能传值,不能传引用,直接给exports赋值,外面无法获取到exports的新值,因此才有了退而求其次的module.exports = { ... }形式。
模块书写格式与模块加载器
在 seajs 里,“加载”一个模块可以有:
seajs.use('a', callback);
require('a');
module.load('a', callback);
首先, seajs.use 仅用来在页面中加载起始入口模块,这就如我们在
nodejs 里,运行模块的入口是:
node filename.js
seajs.use('a', callback) 就相当于 node
filename.js , 仅起到 bootstrap 的作用。
在标准模块里,推荐永远不要出现 seajs. 就如 nodeJS 的模块里,不会出现 node 一样。标准模块的书写形式为:
define(function(require, exports, module) {
// module code
});
这样做的好处,可以使得模块和具体加载器无关。比如 SeaJS 能加载的模块,理论上用 RequireJS 也可以跑起来,因为遵循的模块书写规范有很大交集。CommonJS 社区的一个目标就是使得各种环境下,都遵循统一的模块书写格式。这样,SeaJS, RequireJS, nodeJS 等都只是模块加载器,只要遵循的模块书写规范一致,模块就可以通用。
动态加载
define(function(require, exports, module) {
var a = require('a');
// ...
module.load('b', function(b) {
// ...
});
// ...
});
上面的代码, require('a') 对应的 a.js
模块在 require 执行前就已下载好,require('a') 仅执行
a.js 模块里 define 的 function 参数,以获取模块 a 的 exports. 这种方式是预先加载、按需执行。
而 module.load('b', callback) 是执行到此处时,才开始下载
b.js 模块。下载好后,回调 callback 函数。这种方式是动态延迟加载。
一般来说, require('a') 这种形式用于强依赖,缺了模块
a, 该模块功能就不全了。 module.load 则用于加载可选模块,比如在某些特定条件下才需要的功能。
这两种方式各自的使用场景不同,得具体问题具体分析。
有心人可以发现: module.load 和 seajs.use 是很类似的。内部实现上也的确是公用一套逻辑,唯一不同的是, module.load('path/to/module') 是相对当前模块来定位, seajs.use 是相对当前页面。
总结
目前的 API 设计,已尽量简化,尽量简明易懂。大家有什么好的想法和改进建议,非常欢迎反馈。(建议通过邮件或博客回复给我反馈,文档下面的 DISQUS 很慢,经常漏掉,不可靠。)

2377

被折叠的 条评论
为什么被折叠?



