8

I am using NodeJS and going to write some utility functions. I think of two options here.

The first one is the traditional approach, i.e.

module.exports = {
    random: () => Math.random(),
};

And the second option is to use ES6 class with static methods, e.g.

class MyMath {
    static random() {
        return Math.random();
    }
}
module.exports = MyMath;

From programming/unit testing's perspective which one is better? Or they are pretty much the same because ES6 class essentially is a syntactic sugar?

Update: Thanks for the people who commented. I saw those questions asking class static method v.s. instance method, or prototype methods v.s. object method but mine is more like class static method v.s. Object method.

Eric Xin Zhang
  • 1,230
  • 15
  • 20
  • There is a great article by Cristian Salcescu called [Classes vs Factory function: exploring the way forward](https://medium.freecodecamp.org/class-vs-factory-function-exploring-the-way-forward-73258b6a8d15) – cross19xx Mar 08 '19 at 05:57
  • lol I am at my max flags for today, but this is a duplicate of: https://stackoverflow.com/questions/30783217/why-should-i-use-es6-classes – Steven Stark Mar 08 '19 at 05:57
  • 2
    Possible duplicate of [Why should I use ES6 classes?](https://stackoverflow.com/questions/30783217/why-should-i-use-es6-classes) – cross19xx Mar 08 '19 at 05:58
  • @cr05s19xx thanks for the link. I think it's a bit different. In the first option I am not using a construction function. – Eric Xin Zhang Mar 08 '19 at 06:06
  • I think the dupe proposal does cover a lot of it but I do think this one is separate because of the focus on `static` members. The dupe only mentions that in passing in a single place in a single answer. So I see a valid reason to have somebody go more in-depth in when and why you'd use an ES6+ class with static members as opposed to a plain old object. – VLAZ Mar 08 '19 at 06:06
  • The question is, do you intend the client to do `new MyMath`? – trincot Mar 08 '19 at 06:18
  • Static methods are just global functions with funky names. They are not OOP but procedural programing in disguise. – axiac Mar 08 '19 at 06:46

3 Answers3

5

Using static-only classes as namespaces in JavaScript is the remnant of languages where a class is the only available entity. Modules already act as namespaces.

In case singleton object is needed, object literal should be used:

module.exports = {
    random: () => Math.random(),
};

There's already exports object that can be used:

exports.random = () => Math.random();

Or with ES modules:

export const random = () => Math.random();
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Easier would be `export default { random () { return Math.random() } }`, by using a wrapping object literal for all the module functions and then just call `MyMath.random()` –  Mar 04 '20 at 01:34
  • 1
    @Catalin It's possible to do this with default export but I wouldn't consider it easier. Default export cannot be destructured on import and requires `const { random } = MyMath` to get rid of `MyMath` prefix, while named export can be imported as either `import * as MyMath from '..'` or `import { random } from '..'`. Also, tree shaking is a considerable benefit of ES modules but default export properties cannot be tree-shaken. – Estus Flask Mar 04 '20 at 09:17
1

With the class syntax you might give more than you really intended, it is a constructor that can be invoked with new, while with the object literal syntax you give a non-function object. As that is really what you want to expose, go for that.

trincot
  • 317,000
  • 35
  • 244
  • 286
0

Classes with only static methods are the same as a bunch of isolated functions. In this case you probably don't need to use it. As for unit tests it is pretty much the same since classes with only static methods does not differ that much from functions.