Matt Kuhns
Matt Kuhns

Reputation: 1368

Module vs Class vs Object Literal

This is specific to nodejs.

When is it best to use a module or a class or an object literal?

A module would look like this:

//myModule.js
module.exports = {
    function func1() {
        console.log("func1");
    }
    function func2() {
        console.log("func2");
    }
}

//in another js file
const myModule = require('myModule');
myModule.func1();
myModule.func2();

The class would look something like this. We could also do this the javascript prototype way, but doing this here for simplicity.

//myClass.js
class myClass {
     func1() {
         console.log("Func1");
     }
     func2() {
         console.log("Func2");
     }
}

module.exports = myClass;

//in another js file
const myClass = require('myClass');

let newClass = new myClass();
newClass.func1();
newClass.func2();

Finally, we could have an object literal singleton.

//myObj.js
let myObj = {
    func1: function() {
        console.log("Func1");
    },
    func2: function() {
        console.log("Func2");
    }
};
module.exports = myObj;

//in another js file
let myObj = require('myObj');
myObj.func1();
myObj.func2();

The difference between the class and the object literal is that object literal acts as a singleton; whereas class could have multiple instances.

But what about the difference between an object literal and the module example. Are those exactly the same pattern?

Upvotes: 1

Views: 897

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 371049

But what about the difference between an object literal and the module example. Are those exactly the same pattern?

A class should be used when there's a chance of it being used properly as a class (for example, if you ever want to put or retrieve data on an instance, where that instance also has methods, a class makes perfect sense).

// MyClass.js
class MyClass {
     func1() {
         console.log("Func1");
     }
     func2() {
         console.log("Func2");
     }
     setData(data) {
         this.data = data;
     }
     getData() {
         return this.data;
     }
}

const instance = new MyClass();
instance.setData('foo');
console.log(instance.getData());

But if, as this case appears to be, you only want to collect similar functions together, a class makes the code much more confusing for no real benefit. Readers of the code (which may include yourself, somewhere down the line) will expect a class to be used for something that a plain object can't do.

Your myModule.js is pretty much identical to your myObj.js - both are exporting a plain object which has certain properties on it. The only difference is the existence of the intermediate variable myObj, which isn't used aside from being an intermediate variable.

Defining the object to be exported in a standalone variable before exporting it can help a bit when you want to reliably reference other properties of the exported object:

// a little bit verbose, have to reference `module.exports` every time
// to get to the exported object:
module.exports = {
  getSummary() {
    // using "this" instead may not be reliable without a `bind`
    const { summary } = module.exports.getAllInfo();
    return summary;
  }
  getAllInfo() {
    // ...
  }
};
// a little bit more DRY:
const obj = {
  getSummary() {
    const { summary } = obj.getAllInfo();
    return summary;
  }
  getAllInfo() {
    // ...
  }
};
module.exports = obj;

You also might (or might not) consider defining the object to be exported in a standalone variable to be more readable. You can use whatever you like that suites your use-case.

Upvotes: 1

Related Questions