5

I’m trying to develop a class with static methods on a NodeJs application, as a Config module purpose.
I would like to access to it from different modules without instantiate every time a new object.

1) Is it correct to use an approach like below, avoiding the class prototype?

function Config(){

}

Config.svrPort=function(){
    return 8080;
}

Config.dbName=function(){
    return "myDbName";
}

module.exports = Config;

2) Are there any other solutions?

3) Is it also a valid approach to put different objects in the same module (e.g. config.js) like this?

exports.server=function(){
    return{
        port:8080
    };
};

exports.database=function(){
    return{
        name:"myDbName",
        user:"root",
        password:"myPassword",
        host:"localhost",
        port:3306
    };
};

and finally to use it as:

var config = require('./config');
config.server().port
config.database().name
  • why not just an object literal? –  Jan 04 '16 at 22:44
  • 3
    That is the correct approach although in your example you could simply store the values as primitives: `Config.SVR_PORT = 8080`, also note i rewrote those as "constants", since I don't recommend changing statics. – Andreas Louv Jan 04 '16 at 22:46
  • I agree with @dev-null. Just use `var Config = {SVG_PORT: 8080, ...}`. You can also use `Object.freeze`. – Louay Alakkad Jan 04 '16 at 23:04
  • The latter approach is valid. For the first one you can just `mode.exports = new Config()`, so not exposing the constructor. – eljefedelrodeodeljefe Jan 09 '16 at 11:58

3 Answers3

2

That is the correct approach although in your example you could simply store the values as primitives: Config.SVR_PORT = 8080, note I rewrote those as "constants", since I don't recommend changing statics.

When this is said, then please note: Do not put any sensitive data (passwords, etc) in your JavaScript files, but instead put these in a config file. This will separate config from code. And help you not to leak any potential critical information.

db-secrets.json

{
  "password": "...",
  ...
}

Then you can access the secrets by making a wrapper module:

// Wrapper module for db-secrets.json
var fs = require('fs');
exports = JSON.parse(fs.readFileSync('db-secrets.json'), 'utf8');

Or make a db connect module db-connect.js:

var fs = require('fs');
var db = require('db');
var db_secrets = JSON.parse(fs.readFileSync('db-secrets.json'), 'utf8');

export = function() {
  return db.connect(db_secrets.user, db_secrets.password, ...);
};

If you use git for source control you can easily add the following to your .gitignore which will make sure your sensitive file is not added to git:

.gitignore

db-secrets.json
Andreas Louv
  • 46,145
  • 13
  • 104
  • 123
  • I definitely agree with you to put the sensitive data into a sort of AppConfig JSON file and to wrap it into a module with "exhaustive" Javascript objects. – Domenico Vacchiano Jan 05 '16 at 13:03
1

There are no classes in the prototype languages (it's just a syntax sugar that mimics the classical OOP). Hence no static methods. My guess is that you want a singleton (which is the same as object literal).

var Config = {
    get svrPort() {
        return 8080;
    },

    get dbName() {
        return "myDbName";
    },
};

// updated: https://nodejs.org/api/modules.html#modules_caching
// module.exports = Object.create(Config);
module.exports = Config;
Vidul
  • 10,128
  • 2
  • 18
  • 20
  • Why the `Object.create`? – Louay Alakkad Jan 04 '16 at 23:03
  • @Louy Depends on the [concrete](http://stackoverflow.com/questions/6613261/is-there-any-reason-to-use-object-create-or-new-in-javascript) usage. – Vidul Jan 04 '16 at 23:05
  • @Vidul, just a question: what happens every time that I get a value from this object? Will be created a new instance of the object? Is this like an object with a factory method? – Domenico Vacchiano Jan 04 '16 at 23:17
  • @DomenicoVacchiano Each time the module is `required`, a new object is [created](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create). If you don't want this behaviour, just replace `Object.create(Config)` with `Config`. Getting a value from the [getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) (if I understood the question correctly), does not impose a new object creation. – Vidul Jan 04 '16 at 23:20
  • After the module is `required` for the first time, the value will be cached. Also, I don't see the point of `Object.create` here. –  Jan 04 '16 at 23:49
  • @StefanBaiu There is no caching, it is either a new object or the same one. – Vidul Jan 04 '16 at 23:55
  • @Vidul @DomenicoVacchiano You are mistaken, the object is only created once, and each time the `require()` happens the same object is returned... you're better off simply exporting the singular object. – Tracker1 Jan 05 '16 at 00:03
  • @Tracker1 You mean that `obj = {}; Object.create(obj) === obj; // is true`? – Vidul Jan 05 '16 at 00:08
  • 1
    @Vidul The code in that file will only be executed once. https://nodejs.org/api/modules.html#modules_caching –  Jan 05 '16 at 00:09
  • @Vidul `Object.create(obj) !== obj` ... `require('foo') === require('foo')` .. the code doesn't re-run, require returns the same exports that already processed ... also, there's no point in using the Object.create in this case. – Tracker1 Jan 05 '16 at 00:11
  • @StefanBaiu My error, thank you for the point; the answer was updated. – Vidul Jan 05 '16 at 00:20
1

JS supports object literals, not to mention that you can export a single object, or multiple export properties on the default exports object... When the require('./your-module'); happens the code in the module is not run again, it simply returns the original export, that has it's own original context.


Just export each of the functions/variables that you want as either an object literal, or attached to the exports.

//just declare any private context as it's own variables in your module, these are static
var someVal = "this isn't visible outside the module";

//export single object, with methods attached
//  NOTE: by default exports exists, and is already module.exports
//  exports === module.exports
exports = module.exports = { 
  getSomeVal: function getSomeVal(){
    return someVal;
  },
  getSrvPort: function getSrvPort(){
    return 8000;
  }
  ...
}

//alternatively, export each method as property
//    note, you should name your function assignments, 
//    this helps with debugging.
exports.getDbName = function getDbName(){
  return "mydb";
};

The code only actually runs once and all places using it will see the same option.


As an aside, if you're using Babel with ES6 modules, you can simply declare your export with each method...

export function getSrvPort() {
  return 8000;
}

export function dbName() {
  return "mydb";
}
Tracker1
  • 19,103
  • 12
  • 80
  • 106