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

how to apply the module pattern in a node.js console application?

本文关键字:应用 模块 模式 应用程序 控制台 node js      更新时间:2023-10-06

我正在尝试将此处解释的模块扩充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文件,以便遵循上面链接中讨论的各种增强模式?

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

获取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());

get-set-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中预定义的,所以不要使用"模块"作为变量名,因为你会破坏CommonJS的"模块"名称,这意味着你将无法正确导出API。

通常,在节点中,所有CommonJS模块都自动封装在一个函数中,因此不需要包含IIFE封装代码。包装器代码如下所示:

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

要导出工厂函数(这就是我对该模式的看法),只需将module.exports指定为该函数即可。这在节点中很常见(express这样做,许多连接中间件模块等)。

上面的方法不使用构造函数或原型。它可能更容易理解,但它的缺点是每次都定义新的、不同的getsetinc方法。如果导出的构造函数只访问过原型上定义的方法一次,那么所有实例都可以共享这些方法。有点微优化,但了解如何双向编码是件好事。