最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - NodeJS Module with config - instantiate from require or from module.exports - Stack Overflow

programmeradmin0浏览0评论

I'm developing a node.js module that has several functions.
The module itself will require some config to start (there will be defaults... that can be overridden - file paths for example)

What's the preferred approach when exporting a function? Allowing it to be instantiated from a require statement, and pass in the config object (optional) to the constructor?

var MyModule = require('myModule);

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

myModule.doThing(function(x){

});

Having this in the module:

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

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

Or, creating an instance from the exports statement in the module, then using it like this:

var myModule = require('myModule);

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

myModule.doThing(function(x){

});

Instead, having this in the module:

module.exports = exports = MyModule();

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

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

I'm developing a node.js module that has several functions.
The module itself will require some config to start (there will be defaults... that can be overridden - file paths for example)

What's the preferred approach when exporting a function? Allowing it to be instantiated from a require statement, and pass in the config object (optional) to the constructor?

var MyModule = require('myModule);

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

myModule.doThing(function(x){

});

Having this in the module:

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

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

Or, creating an instance from the exports statement in the module, then using it like this:

var myModule = require('myModule);

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

myModule.doThing(function(x){

});

Instead, having this in the module:

module.exports = exports = MyModule();

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

    function doThing(cb){
        //do stuff
        cb();
    }
}
Share Improve this question asked Jan 12, 2013 at 1:42 AlexAlex 38.6k54 gold badges214 silver badges340 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 6

I’ll say let you users provide an object when instanciating, put the defaults in the prototype. You may also want to provide a configure function, this allows you (now or in the future) to validate keys/values, and your users to set configs after instanciation.

// 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');

EDIT

As Jake Sellers noted in the ments, this isn’t standard API pattern in CommonJS modules. A better solution would be to export a function that returns whatever object you’re creating.

More importantly, I should not advise to put the config in the prototype, ever. Doing this makes the config object shared by all children. As such any modification on it will also affect all children. Shame on me, I wasn’t a beginner when I wrote this crap. Double thanks Jake ;)

A better implementation:

// 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');

It depends on whether you want the users of your module be able to use exactly one pre-defined instance (the one that you create on module.exports) or if you want them to be able to create their own instances (then you need to export the constructor as a function, not its return value).

If you go and write a constructor, I'd opt for the second option (let the user create the instances) - except if it's a singleton object you are providing.

发布评论

评论列表(0)

  1. 暂无评论