【问题标题】:NodeJS Module with config - instantiate from require or from module.exports带配置的 NodeJS 模块 - 从 require 或 module.exports 实例化
【发布时间】:2013-01-12 01:42:29
【问题描述】:

我正在开发一个具有多种功能的 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();
    }
}

【问题讨论】:

    标签: javascript node.js


    【解决方案1】:

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

    // 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 在 cmets 中指出的,这不是 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');
    

    【讨论】:

    • 真的很喜欢这个。 i1 和 i2 有什么区别?
    • 真的没有,第 7-9 行确保如果用户没有实例化而只是像函数一样调用构造函数,我们会为他实例化。第 7 行检查 this 是否是 Mod 的新创建实例,如果不是,第 8 行创建并返回一个,将用户提供的配置传递给构造函数,因此具有完全相同的效果。
    • 我想我明白了。我还有另一个相关问题(虽然超出了这个问题的范围) - stackoverflow.com/questions/14300411/…
    • 什么?您仍在调用 require 然后 new 或构造函数...这不是 npm 所需的任何模块的使用方式...
    • 对,这不是标准模式。我自己不做。由于问题中缺乏语义信息,我提出了这个解决方案来接近 Alex 的实现。我用通用注释进行了编辑。
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2023-03-06
      • 2016-03-15
      • 2019-04-05
      • 2013-05-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 2018-01-16
      • 2015-12-02
      相关资源
      最近更新 更多