What's the recommended way of creating objects in NodeJS?

tounano picture tounano · Dec 16, 2013 · Viewed 70.4k times · Source

I'm building a composite for request module, however I'm not sure what's the best practice regarding building objects in JS for Node.

Option 1:

function RequestComposite(request) {
  return {
    get: function (url) { return request.get(url); }
  }
}
var comp = RequestComposite(request);
  • Note: I know that i should call a CB in async way, but for the ease of explaination I return it...

Option 2:

function RequestComposite(request) {
  this.request = request;
}

RequestComposite.prototype.get = function (url) { return this.request.get(url); };
var comp = new RequestComposite(request);

Option 3:

var RequestComposite = {
  init: function (request) { this.request = request; },
  get: function (url) { return request.get(url); }
}
var comp = Object.create(RequestComposite).init(request);

I tried to find my way around, however I got even more confused about how should I use objects...

Would the answer be different if I want to use objects for browsers?

Thanks.

Answer

bgusach picture bgusach · Dec 16, 2013

The most efficient way is the following:

  • Put all the essential initialisation in the constructor (e.g. validate constructor parameters, set properties, etc).

  • Set methods in the .prototype property of the constructor. Why? Because this prevents from re-writing each method each time you create an object. This way you recycle the same prototype for each object you create. Efficient in memory and sparing coding time.

  • Do not use closures for private properties. Why? It is slow, and prevents you from using this object in an inheritance chain (the pseudo-private vars don't belong to the object, they're just accessible). It is instead common practice to use an underscore when declaring an object property, to indicate it is a _private property that should not be accessed from outside.

  • Use new instead of Object.create. It's easier to remember if you are used to other OOP languages; and at the end new uses Object.create under the hood.

In other words, something like this:

var Person = function (name) {
    this._name = name;
};

Person.prototype.sayHello = function () {
    alert('My name is: ' + this._name);
};

var john = new Person('John');
john.sayHello();

EDIT

Some extra information:

  • Object.create vs new. Benchmark here. Although the question is for Node.js, I think the same behaviour is to be expected. (any correction is welcome)

  • Closures to emulate private properties: You can read about in this question.. The point that the private/closure properties do not belong to the object is a programming fact: they are accessible by the object methods but do not belong to the object. When using inheritance, that is a big mess. Besides, only methods that are declared in the constructor have access to the closure. Methods defined in the prototype do not.

  • Defining methods in the constructor or the prototype property: read this question, and take a look of this benchmark

EDIT 15/04/2016

The points I made here three years ago are still right from a performance point of view, but my opinion about what is the "recommended way" has changed a little in the meanwhile. Factory functions are in general a good option, which would be the OP's first approach. Just an example:

function Person(name) {
    return {
        sayHello: function () { alert('My name is: ' + name); }
    };
}

and then just do:

var p = Person('John');

In this case you trade flexibility (no new coupling, ease of composition with other "mix-ins") and simplicity (no this mess, easy object instantiation) for some speed and memory. In general they are perfectly valid. If you have performance issues, and those are because of this way of creating objects, revert to another method. The Object.create approach is also good, falling somehow in the middle of new and factory functions (side note: the new class syntax is syntactic sugar for new+ prototype)

Summing up: my recommended way is starting from the simplest and easiest way of creating objects (factory functions) and then fall to other methods when you hit performance issues (which in most of cases is never).