关于CommonJS中Module实现的问题

2011-04-28 12:22:06 +08:00
 real_newbie
原生的JavaScript中可以通过Closure来实现模块化. 比如像这里所做的这样: http://yuiblog.com/blog/2007/06/12/module-pattern/

在CommonJS的实现中, 是这样做的: http://wiki.commonjs.org/wiki/Modules/1.1#Sample_Code

CommonJS中的这种module的方式是怎么实现的呢?
8586 次点击
所在节点    JavaScript
31 条回复
real_newbie
2011-04-28 13:12:57 +08:00
是不是CommonJS中的所谓Module和Yuiblog里所说的Module其实不是同一个概念?

前者只是单纯的把不同的function放到了不同的文件里, 加入了require的机制; 后者可以进行一些类似数据封装的工作?
kuno
2011-04-28 19:38:12 +08:00
commonJS的module只是社区的一个proposal, 目前只有node.js部分实现了它。
不过,目前看起来下一个版本的ecmascript的module系统会不太一样,
兰州可以参考这个视频里的内容,
<amp-youtube data-videoid="hs6tF-RDX4U" layout="responsive" width="480" height="270"></amp-youtube>
kuno
2011-04-28 19:42:55 +08:00
刚看了commonJS的wiki,原来还有很多的其他系统也实现了。
更正一下, :(
real_newbie
2011-04-28 19:46:49 +08:00
@kuno,

感谢回复, CommonJS的实现并不是只有node.js, 像SproutCore, CouchDB之类的也有实现. (CommonJS的Spec有实现的列表)

你给出的那个视频好像是介绍下一代JavaScript中如何实现module的吧?(抱歉, 没仔细看视频, 只看了标题和开头). 我目前在做的东西是基于CouchDB的, 所以我想知道是关于CommonJS的, 而不是下一代JavaScript的实现.

不管怎么样, 还是非常感谢你~
aligo
2011-04-28 19:47:06 +08:00
数据封装是什么意思?
一般控制访问的话,return返回的是一个匿名函数或者对象,作为闭包,可以访问scope的东西,但是调用那个module的时候就用不了了

yui的module就是基于这个基本原理包装起来的,这样就不会因为随便操作一般对象的prototype产生问题
real_newbie
2011-04-28 19:52:13 +08:00
@aligo,

对于yui的module我是理解的, 就和你说的一样.
aligo
2011-04-28 19:56:22 +08:00
CommonJS的那个require应该就是
function(jsfile){
var exports = {};
然后这里执行js文件里的代码
return exports;
}
real_newbie
2011-04-28 20:00:34 +08:00
@aligo,

所以其实和yui的module是两个不同的概念, 是这样子吗?
aligo
2011-04-28 20:08:05 +08:00
@real_newbie 一样是闭包,不过如果那玩意要在客户端使用require,必须是像jsonp一样,完整的代码是:
do_export(function(){
var exports = {};
然后这里执行js文件里的代码
return exports;
});

不过这样的动态载入无故增加http请求数量,实在多余,一般是把所有js文件打包成一个,压缩之后要求客户端缓存
real_newbie
2011-04-28 20:17:02 +08:00
@aligo,

我觉得不一样, 就拿主帖子中CommonJS Spec里的例子来讲. 我觉得如果是和yuiblog里一样的话, math.js应该改成下面这样样子, 才是一样的:

exports.add = fuction() { return function() {
var sum = 0, i = 0, args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
};

然后再require的时候要这个样子:

var add = require('math').add();
aligo
2011-04-28 20:28:32 +08:00
恩,你这个意思我明白,是要在exports.add有似有变量吧,不过你这个也不对,应该是:
exports.add = fuction() {
var args = arguments;
return (function(arguments) {
var sum = 0, i = 0, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
})(arguments);
};

但是我上面说的是,你要给前端使用的话,只有在上面这段代码的东西的基础上,再包裹
do_export(function(){
var exports = {};
上面的代码
return exports;
});

同时预先定义好do_export,用以接受require发出的http jsonp请求,但是这里有一个问题,浏览器的js貌似要blocking i/o等待require发起的异步请求返回是一件相当麻烦的事情了

不知道你看懂了我说的没有。。。
aligo
2011-04-28 20:29:11 +08:00
订正:
exports.add = fuction() {
var args = arguments;
return (function(args) {
var sum = 0, i = 0, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
})(args);
};
real_newbie
2011-04-28 20:32:21 +08:00
@aligo,

抱歉, 我一开始就没讲明白, 我并不是要在前端使用的. 是用在Server端的.

exports.add = fuction() {
var args = arguments;
return (function(arguments) {
var sum = 0, i = 0, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
})(arguments);
};

这个不和我的require('math').add(); 只是你这一版本的应该还是require('math).add, 不用加"()"进行调用, 对吧?
aligo
2011-04-28 20:42:03 +08:00
@real_newbie 恩,我只是和你地址里的那个代码实现一样的东西var add = require('math').add;而不是var add = require('math').add();

不过扯远了,我要说的是module这东西,用来实现通过scope进行访问控制是可以的,就像yui那样

然后如果前端使用它是为了分开文件就没有必要了,而这里的require实现的包括exports,对于每个文件是相互独立的,实现原理应该就是#7的那样,对于不同环境当然有不同实现,不过你这样去理解就够了
real_newbie
2011-04-28 20:46:38 +08:00
@aligo,

呵呵, 事实上你#11里讲的关于前端的那一段我的确没有看的太明白. 不过因为我是用在Server端的, 所以就不关心啦;)
aligo
2011-04-28 20:52:50 +08:00
@real_newbie 恩,其实就是前端要实现require动态载入js的话,就是动态插入script标签,必然事先得提供一个do_export函数用来接受闭包
aligo
2011-04-28 20:56:04 +08:00
@real_newbie 主要是你提到了yui,我以为你要在前端实现这个require,于是劝你放弃
real_newbie
2011-04-28 21:04:19 +08:00
@aligo,

恩, 提到yui, 主要是因为我理解yui的这种方式, 所以想进行对比下.

另外off topic, 前端的话, 好像有这个玩意: https://github.com/jrburke/requirejs

不过似乎压缩以后还是显的有点过大了.
aligo
2011-04-28 21:13:25 +08:00
@real_newbie 恩,这个东西well-scoped module就是用define()包裹新加入的js,类似我刚才说的do_export()

不过一般用用直接插入script标签就够了,不过意义不大,因为这增加了http请求次数,一般需求都是把js合并后各种压缩成一个
kuno
2011-04-29 10:14:46 +08:00
根据我使用node.js的经验,commonJS的实现并没有使用closure.
在node里面,module是一个特别的全局对象,有一个exports的属性。所有能够被调用的对象又都是exports的成员。当一个这个module通过require('MODULE_NAME')被调用之后,exports包含的成员就被载入了当前客户端global scope, 成为一个全局对象了。


function require(jsfile) {
var module = eval(do_some_io(jsfile));

return moduel.exports;
}

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/12256

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX