如何在node.js控制台应用程序中应用模块模式?

时间:2015-02-13 00:32:30

标签: javascript node.js

我正在尝试将解释here的模块扩充JavaScript模式应用于控制台node.js应用程序。

首先我有文件get-set.js,它实现了一个只有getset方法的简单模块:

var module = (function() {
    var x = 0;
    function get() {return x;}
    function set(_x) {x = _x;}
    return {
        get: get,
        set: set};
})();

module.set(10);
console.log(module.get());

以上代码有效。 现在,我正在尝试按照模式中的下一步并在单独的文件get-set-inc.js中找到一些额外的功能(比如增加计数器的方法):

require('./get-set.js');

var module = (function(m) {
    function inc() {m.set(m.get()+1);}
    m.inc = inc;
    return m;
})(module);

module.inc();
console.log(module.get());

不幸的是,当我在node.js下运行后一个文件时,我没有成功扩充模块。事实上我得到了:

$ ls
get-set-inc.js  get-set.js
$
$ node get-set-inc.js 
10

[...]/get-set-inc.js:4
        function inc() {m.set(m.get()+1);}
                                ^
TypeError: Object #<Module> has no method 'get'
    at Module.inc ([...]/get-set-inc.js:4:33)
    at Object.<anonymous> ([...]/get-set-inc.js:9:12)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:929:3

经过进一步检查,我逐渐意识到问题在于使用require。那么我应该如何在node应用程序中加载外部JavaScript文件,以便我可以按照上面链接中讨论的各种增强模式进行操作?

1 个答案:

答案 0 :(得分:2)

首先是代码,然后是下面的一些注释。

获取-set.js

module.exports = function gsFactory() {
  var x = 0;

  function get() {
    return x;
  }

  function set(_x) {
    x = _x;
  }
  return {
    get: get,
    set: set
  };
}

//prints 0
console.log(module.exports().get());

获取 - 组 - inc.js

var gs = require('./get-set');

module.exports = function gsiFactory() {
  var instance = gs();
  function inc() {
    instance.set(instance.get()+1);
  }
  instance.inc = inc;
  return instance;
};

// demo
var gsi = module.exports();
gsi.inc();
// this prints 1
console.log(gsi.get());
gsi.inc();
// this prints 2
console.log(gsi.get());

node get-set-inc.js
0
1
2

这就是我打算建立的东西。一个问题是module是由包装函数在node.js中预定义的,所以不要使用&#34; module&#34;作为一个变量名,因为你会破坏CommonJS&#34;模块&#34;名称意味着您无法正确导出您的API。

通常在节点中,所有CommonJS模块都自动包装在一个函数中,因此不需要包含IIFE包装器代码。 wrapper code看起来像这样:

NativeModule.wrapper = [
  '(function (exports, require, module, __filename, __dirname) { ',
  '\n});'
];

要导出工厂函数(这是我对此模式的看法),只需将module.exports指定为该函数即可。这在节点中非常常见(表达了这种情况,许多连接中间件模块等)。

上面的方法并没有使用构造函数或原型。它可能更容易理解,但它的缺点是每次都定义新的getsetinc方法。如果导出的构造函数访问原型上只定义一次的方法,则所有实例都可以共享这些方法。一点微优化,但了解如何以两种方式编码是很好的。