Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

use `module` as namespace

I've been using a pattern in my node.js modules that seems so obvious to me that I assume there must be something wrong with it or I would see more people doing it. To keep private variables that are global to the module, I simply attach them as properties on the module object. Like so:

module.exports = {

  init: function() {
    module.someClient = initializeSomethingHere()
  },

  someMethod: function(done) {
    module.someClient.doSomething(done)
  }
}

This seems preferable to me than something like this...

var someClient;

module.exports = {
  init: function() {
    someClient = initializeSomethingHere()
  },

  someMethod: function(done) {
    someClient.doSomething(done)
  }
}

...because in the second example you need to go searching for var someClient at the top of the file to make sure that the omission of the var keyword is intentional within the init method. I've never seen this pattern used elsewhere though, so I wonder if I'm missing something that makes it less than ideal.

Thoughts?

like image 963
Ben Avatar asked Apr 06 '16 02:04

Ben


2 Answers

There are a couple of possible downsides that come to mind.

1) It's technically possible for those properties to be accessed and modified outside the module, but only if a reference to the module itself is available outside it. Something that makes the module available through its own exports (module.exports = module; being the simplest example) would expose them.

2) You could have a naming conflict with a builtin property or a future builtin property that doesn't exist yet (which would cause your code to break in future versions of node.js). This could be very problematic and very hard to debug. Currently the built-in properties on a module object are: children, exports, filename, id, loaded, paths, and parent.

because in the second example you need to go searching for var someClient at the top of the file to make sure that the omission of the var keyword is intentional within the init method.

If that is the reason, you could just use a namespace that isn't module. For instance by adding var private = {}; to the top of each file and then using private.someClient instead of module.someClient.

Also 'use strict'; so that the accidental omission of var is an error and not an accidental global.

like image 161
Paul Avatar answered Nov 05 '22 08:11

Paul


Drawbacks

  • Option 1: This practice is prone to naming conflict with a builtin property or a future builtin property that doesn't exist yet, as @paulpro stated in his answer.

  • Option 2: If you miss var keyword and expose the someClient globally. Besides you need to go searching for var someClient at the top of the file all the time.

Alternative

As JavaScript has function scope it's better to define everything within a function. Creating private and public members within a function. Below is a design pattern which one can follow:

'use strict';

module.exports = (function(){

  //private
  var someClient;

  //public properties
  var that={};

  that.init = function() {
    someClient = initializeSomethingHere()
  },

  that.someMethod: function(done) {
    someClient.doSomething(done)
  }

  //expose only the required methods
  return that;
})();

Here only exposed methods are those which are attached to that object. And all rest are private to the function scope. Even if you miss the var keyword in someClient it won't be accessible out side of the function, which won't ever happen if you use 'use strict' at the top.

Logic is first time when you require the xyz.js file it will return the that object rather than the function.

like image 40
Nivesh Avatar answered Nov 05 '22 07:11

Nivesh