3

我正在开发一个具有多个功能的 node.js 模块。
模块本身需要一些配置才能启动(会有默认值......可以被覆盖 - 例如文件路径)

导出函数时首选方法是什么?允许从 require 语句实例化它,并将配置对象(可选)传递给构造函数?

var MyModule = require('myModule);

var myModule = new MyModule({
    name: "test name"
});

myModule.doThing(function(x){

});

在模块中有这个:

module.exports = function MyModule(){
        MyModule.prototype.config = {name: "default name"}

            function doThing(cb){
                //do stuff
                cb();
            }
}

或者,从模块中的 exports 语句创建一个实例,然后像这样使用它:

var myModule = require('myModule);

myModule.config = {name: "test name"}

myModule.doThing(function(x){

});

相反,在模块中有这个:

module.exports = exports = MyModule();

function MyModule(){
MyModule.prototype.config = {name: "default name"}

    function doThing(cb){
        //do stuff
        cb();
    }
}
4

2 回答 2

6

我会说让您的用户在实例化时提供一个对象,将默认值放在原型中。您可能还想提供一个配置功能,这允许您(现在或将来)验证键/值,并且您的用户可以在实例化后设置配置。

// Module

var Mod = module.exports = function Mod (opts) {
  opts = (opts === Object(opts)) ? opts :  {};

  // This allows users to instanciate without the `new` keyword
  if (! (this instanceof Mod)) {
    return new Mod(opts);
  }

  // Copy user provided configs to this.config
  for (var key in opts) if ({}.hasOwnProperty.call(opts, key)) {
    this.config[key] = opts[key];
  }
};

Mod.prototype.config = {
  foo : 'foo',
  bar : 'bar'
};

Mod.prototype.configure = function configure (key, val) {
  this.config[key] = val;
  return this;
};

// Usage

const Mod = require('/path/to/mod');

var i1 = new Mod;

var i2 = Mod();

var i3 = new Mod({
  foo: 'bar'
});

var i4 = Mod({
  foo: 'bar'
});

i4.configure('bar', 'baz');

var i5 = (new Mod).configure('bar', 'baz');

编辑

正如 Jake Sellers 在评论中指出的那样,这不是 CommonJS 模块中的标准 API 模式。更好的解决方案是导出一个返回您正在创建的任何对象的函数。

更重要的是,我永远不建议将配置放入原型中。这样做会使所有孩子共享配置对象。因此,对它的任何修改也会影响所有孩子。真丢人,写这篇废话的时候我还不是初学者。双重感谢杰克;)

更好的实现:

// Keep defaults private
var defaults = {
  foo : 'foo',
  bar : 'bar'
};

// Construct
var Mod = function Mod (opts) {
  opts = (opts === Object(opts)) ? opts :  {};

  // This allows users to instanciate without the `new` keyword
  if (! (this instanceof Mod)) {
    return new Mod(opts);
  }

  this.config = {};
  // Copy user provided configs to this.config or set to default
  for (var key in defaults) if (defaults.hasOwnProperty(key)) {
    if ({}.hasOwnProperty.call(opts, key)) {
      this.config[key] = opts[key];
    }
    else {
      this.config[key] = defaults[key];
    }
  }
};

// Let the user update configuration post-instanciation
Mod.prototype.configure = function configure (key, val) {
  this.config[key] = val;
  return this;
};

// Export a function that creates the object
exports.createMod = function createMod (opts) {
  return new Mod(opts);
};

// Export the constructor so user is able to derive from it
// or check instanceof
exports.Mod = Mod;

// USAGE

var mod = require('/path/to/mod');

var i1 = mod.createMod({ foo : 'bar' });

i1.configure('bar', 'baz');
于 2013-01-12T14:59:01.090 回答
1

这取决于您是否希望模块的用户能够仅使用一个预定义的实例(您在module.exports其上创建的实例),或者您是否希望他们能够创建自己的实例(然后您需要导出构造函数作为一个函数,而不是它的返回值)。

如果你去写一个构造函数,我会选择第二个选项(让用户创建实例)——除非它是你提供的单例对象。

于 2013-01-12T15:02:28.953 回答