Differences between creating a new class to using export const

Setup:

  • BabelJS (es2015, react, stage-1)
  • Webpack
  • React / redux

New to CommonJS and ES6. I know the difference between an object instance and a static container of methods but I am not sure how they behave when separated to modules. So I wonder what are the differences between returning an instance (is this pattern valid at all?):

// StateParser.js

class StateParser {
    constructor() {
     }

     method1() {
        ...
     }

}

export default new StateParser()

and exporting const methods:

// StateParser.js

let state = {
}

export const method1 = () => { ... }
  1. Method A: Would there be a new instance every time I import?
  2. Method B: Is one of the benefits the ability to use object destructuring:

    import { method1 } from '../utils/StateParser.js';
    

    and then use method1 as if it existed locally?

  3. Method A: Is one of the benefits the ability to initialize state in the constructor?

So basically I am not sure when to use which for my utility classes and would appreciate your input.


Solution 1:

Would there be a new instance every time I import A?

No, modules are only evaluated once.

Is one of the benefits of B the ability to use object destructuring and then use method1 as if it existed locally?

Yes, though it's not called "destructuring". They're named imports (or named exports of the module), and they don't nest and use a different syntax for aliasing.

Is one of the benefits of A the ability to initialize state in the constructor?

No. You can initialise module state just directly in the module scope as well, you don't need a constructor function for that.

But yes, if you have state in the instances, it's a good idea to use a class which you can instantiate multiple times. For that, you need to export the class itself, not an instance, of course.

Is the export default new … pattern valid at all?

No, it's an antipattern for the reasons outlined above. Given the class is used nowhere else, it's quite similar to the anonymous class antipattern. And exporting multiple named exports is much better than default-exporting objects anyway.

Solution 2:

We don't recommend exporting an evaluation (e.g. new StateParser()) for several reasons.

In this case, the module exports the result which is only evaluated once (also mentioned by @Bergi). This is rarely the desired outcome, but if it is, a Singleton pattern should be used instead. Some ES6 module benefits are lost (tree-shaking and faster access to imports), it makes imports slower and makes them possible to cause side-effects which should rather happen upon invocation. I also think this is an anti-pattern and the drawbacks can be avoided via exporting a function or class.

It would make more sense to compare export default StateParser with exporting const methods.

See also:

  • All exports are static
  • ES6 modules are only evaluated once
  • Lost ES6 benefits