JavaScript ComomJS 的模块系统设计得好吗?

jiyinyiyong · 2013年10月05日 · 最后由 jiyinyiyong 回复于 2013年10月05日 · 3588 次阅读

CommonJS 规范里的模块系统.. http://wiki.commonjs.org/wiki/Modules/1.1.1 math.js

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

increment.js

var add = require('math').add;
exports.increment = function(val) {
    return add(val, 1);
};

program.js

var inc = require('increment').increment;
var a = 1;
inc(a); // 2

module.id == "program";

先不说浏览器上边,因为异步,RequireJS 指出 CommonJS 问题不少.. 单说服务端编程的话,感觉用这样的写法比较少见啊, 通常的 require 或者 import, 加载模块后模块中函数就直接到代码作用域当中了, 而 CommonJS 里引入后仅暴露一个对象,至于其他 JS 方言会额外提供语法直接引入方法, 甚至 ES6 规范里的 import 也和 CommonJS 不同..

个人是感觉上手挺简单的... 而且单 Node 社区用,也没有明显的问题报过, 但总的感觉有点怪异,为什么其他语言都采用引用后直接暴露方法的方式呢?

为什么其他语言都采用引用后直接暴露方法的方式呢? 请给一个例子,好让我能正确理解你的想法。

#1 楼 @xds2000 其他见到的加载模块的语句,require 或者 import 都没有返回值. 抄代码

# cat lib/hola.rb
class Hola
  def self.hi
    puts "Hello world!"
  end
end
# irb
>> require 'hola'
=> true
>> Hola.hi
Hello world!

这个和 CommonJS 的返回值做对比,,

require 在 ruby 语言中是关键字。但 commonJS 定义的 require 是一个 function,一定是有返回。这是我理解的。

因为 Javascript 没有模块机制...

其实 Node 也可以这么写:

user.js

GLOBAL.user = {
  name: "Hello",
  sex: "world"
}

app.js

require("./user");

console.log(user.name);

eval

› node -i app.js
Hello

这样的话你会得到一个完整的结果。当然在这里,require 的默认返回是 module.exports 也就是 {}, 这是规范。

如果你想让 node 来模拟 Ruby 的 require 方式当然也是可以的:

user.js

GLOBAL.user = {
  name: "Hello",
  sex: "world"
}
module.exports = true;

这样的话,每次 require('./user') 都能拿到返回值 true.

那么为毛 CMD 规范要这么蛋疼的给你一个返回值域呢?因为 Javascript 没有模块机制。

变量名很容易冲突。这点跟 C 一样,所以前辈们用了很多种方式来规避这一点。详情请看各种 Module Pattern. 写 C 也是一样的,畏畏缩缩的写个库,最后怕跟别人冲突都得加个前缀...

当然,给 module 一个返回值就是规避如今这种冲突的一个有效方式。首先所有的 module 都被 function 所包裹,变量名不会随意的外泄,当我需要某个 module 的时候我就 require 他。难道不好?

如果每个 require 最终没有返回值,其实是开了历史的倒车。因为变量必须注册在 GLOBAL 域上,要不然没法在 require 之后便拥有这个变量。而最原始的 Javascript 写法就是这样写的。

个人觉得 CommonJS 的模块的引用很好,只暴露 module 对象给引用他的 module,并且分配给一个新的变量,这个变量也可以看成是 namespace,这样用户可以决定使用什么 namespace,以区分已有的 namespace,造成冲突的时候直接修改 namespace 是很简单的事。

#4 楼 @Saito 嗯,对 JS 来说是不错了,而且直接避免了循环依赖的问题. 主要还是多疑吧,因为没看到先例,采取了大多数语言不采用的方案,不清楚是否有没考虑到. 其他语言不采用这种方案,是不是出于数据类型方面的考虑,表结构不是普遍自由的?

需要 登录 后方可回复, 如果你还没有账号请 注册新账号