1
real_newbie OP 是不是CommonJS中的所谓Module和Yuiblog里所说的Module其实不是同一个概念?
前者只是单纯的把不同的function放到了不同的文件里, 加入了require的机制; 后者可以进行一些类似数据封装的工作? |
2
kuno 2011-04-28 19:38:12 +08:00
commonJS的module只是社区的一个proposal, 目前只有node.js部分实现了它。
不过,目前看起来下一个版本的ecmascript的module系统会不太一样, 兰州可以参考这个视频里的内容, |
3
kuno 2011-04-28 19:42:55 +08:00
刚看了commonJS的wiki,原来还有很多的其他系统也实现了。
更正一下, :( |
4
real_newbie OP @kuno,
感谢回复, CommonJS的实现并不是只有node.js, 像SproutCore, CouchDB之类的也有实现. (CommonJS的Spec有实现的列表) 你给出的那个视频好像是介绍下一代JavaScript中如何实现module的吧?(抱歉, 没仔细看视频, 只看了标题和开头). 我目前在做的东西是基于CouchDB的, 所以我想知道是关于CommonJS的, 而不是下一代JavaScript的实现. 不管怎么样, 还是非常感谢你~ |
5
aligo 2011-04-28 19:47:06 +08:00
数据封装是什么意思?
一般控制访问的话,return返回的是一个匿名函数或者对象,作为闭包,可以访问scope的东西,但是调用那个module的时候就用不了了 yui的module就是基于这个基本原理包装起来的,这样就不会因为随便操作一般对象的prototype产生问题 |
6
real_newbie OP |
7
aligo 2011-04-28 19:56:22 +08:00
CommonJS的那个require应该就是
function(jsfile){ var exports = {}; 然后这里执行js文件里的代码 return exports; } |
8
real_newbie OP |
9
aligo 2011-04-28 20:08:05 +08:00
@real_newbie 一样是闭包,不过如果那玩意要在客户端使用require,必须是像jsonp一样,完整的代码是:
do_export(function(){ var exports = {}; 然后这里执行js文件里的代码 return exports; }); 不过这样的动态载入无故增加http请求数量,实在多余,一般是把所有js文件打包成一个,压缩之后要求客户端缓存 |
10
real_newbie OP @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(); |
11
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发起的异步请求返回是一件相当麻烦的事情了 不知道你看懂了我说的没有。。。 |
12
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); }; |
13
real_newbie OP @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, 不用加"()"进行调用, 对吧? |
14
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的那样,对于不同环境当然有不同实现,不过你这样去理解就够了 |
15
real_newbie OP |
16
aligo 2011-04-28 20:52:50 +08:00
@real_newbie 恩,其实就是前端要实现require动态载入js的话,就是动态插入script标签,必然事先得提供一个do_export函数用来接受闭包
|
17
aligo 2011-04-28 20:56:04 +08:00
@real_newbie 主要是你提到了yui,我以为你要在前端实现这个require,于是劝你放弃
|
18
real_newbie OP @aligo,
恩, 提到yui, 主要是因为我理解yui的这种方式, 所以想进行对比下. 另外off topic, 前端的话, 好像有这个玩意: https://github.com/jrburke/requirejs 不过似乎压缩以后还是显的有点过大了. |
19
aligo 2011-04-28 21:13:25 +08:00
@real_newbie 恩,这个东西well-scoped module就是用define()包裹新加入的js,类似我刚才说的do_export()
不过一般用用直接插入script标签就够了,不过意义不大,因为这增加了http请求次数,一般需求都是把js合并后各种压缩成一个 |
20
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; } |
21
aligo 2011-04-29 11:53:03 +08:00
@kuno 我试了一下
bar.js: var foo = 'bar' exports.bar = function () { return foo } foo.js: require.paths.unshift('.') var bar = require('bar') console.log(typeof bar.foo == 'undefined') console.log(typeof bar.bar == 'function') console.log(bar.foo) console.log(bar.bar()) node foo.js结果是: true true undefined bar 这里新require进来的js并不是一个global scope,如果拿来和ruby比较的话 module Bar BAR = 'bar' def ... end 然后在别的地方是可以Bar::BAR的 |
22
real_newbie OP |
23
aligo 2011-04-29 11:57:51 +08:00
@kuno 并且如果再加入一个rab.js如下
exports.rab = function () { return exports.bar() } 然后在原来的的foo.js var rab = require('rab') console.log(rab.rab()) 这样是会出错的 |
24
aligo 2011-04-29 12:02:53 +08:00
@kuno 最后,再创建一个oof.js:
exports.oof = function () { return oof_text } exports.test_oof = function () { return typeof oof_text == 'undefined' } foo.js改为: var oof_text = 'oof!' require.paths.unshift('.') var oof = require('oof') console.log(oof.test_oof()) console.log(oof.oof()) 你会看到true然后出错 |
25
real_newbie OP 我不明白这个所谓global scope是什么意思.
如果要复用bar()似乎应该是这样子做: function bar() {} exports.bar = function() { return bar(); } exports.rab = function() { return bar(); } |
26
aligo 2011-04-29 12:06:17 +08:00
总之我要说的是这里require进来的东西就是module,每个js都是自己的scope,只有通过exports.的东西才会被require返回,但是这个exports在次require之间也是互相独立的
|
27
aligo 2011-04-29 12:13:13 +08:00
然后再来玩个新的bar.js:
var foo = 'b' var_foo = 'ar' Bar = function () { return foo + var_foo } 然后这是新foo.js require.paths.unshift('.') require('bar') console.log(typeof bar == 'undefined') console.log(typeof var_bar == 'undefined') console.log(typeof Bar == 'function') console.log(Bar) console.log(Bar()) console.log(bar) console.log(var_bar) 结果是 true true true [Function] bar 到最后2个就出错了 |
28
n2n3 2011-04-29 12:25:47 +08:00
node.js 就是如 #7 @aligo 所说用 closure 实现的吧
https://github.com/joyent/node/blob/master/src/node.js#L420 https://github.com/joyent/node/blob/master/lib/module.js |
29
real_newbie OP |
30
real_newbie OP @n2n3, 果然还是源代码最高啊. module.js里的"Module._load"很清楚了.
|
31
aligo 2011-04-29 15:06:03 +08:00
恩,所以继续离题一下,如果要在前端里实现这样的效果,就需要像你上面提到的那个requirejs那样,在每个js中用一个define()包裹,像#9那样
|