I've noticed there are two different ways to effectively write a class (or class-like thing) in JavaScript. Using a simple counter class as an example:
A real class (used as new Counter1())
class Counter1 {
constructor(count = 0) {
this.count = count;
}
inc() {
this.count++;
}
get() {
return this.count;
}
}
A function returning an object (used as Counter2())
function Counter2(count = 0) {
return {
inc() {
count++;
},
get() {
return count;
},
};
}
I have a lot of code that could be written in either one of these styles. Which should I use?
This is my understanding:
Counter1 can be used with instanceof and inheritance, but is more verbose and doesn't have real private properties (eg count property is exposed).
Counter2 is more concise and has real private methods/state (just local variables in the function), but can't be used with instanceof and inheritance. It also creates new copies of the inc and get functions for each instance, which may impact performance? I don't know.
I put it in a jsperf page here to test the speed of new instance creation in either style: https://jsperf.com/class-vs-object-2
Here are the results on my computer (new instances created per second):
Test Chrome Firefox Edge
new Counter1(); 217,901,688 2,086,800,399 31,106,382
Counter2(); 30,495,508 36,113,817 9,232,171
I don't know why the Firefox number with class is so high (hopefully it didn't notice the code had no effect and elide the whole thing) or why the Edge numbers are so low.
So at least with regards to performance, a real class is much faster, probably because it avoids the overhead of creating a new copy of the methods for each instance.
While the verbosity and lack of private state with classes is annoying, I think the performance benefit is more important, but it depends on the situation.
Edit
I've made the test call inc() and get() on the resulting object as well and the numbers are basically the same:
Test Chrome Firefox Edge
new Counter1(); 215,352,342 2,072,278,834 23,570,036
Counter2(); 14,309,836 35,564,201 9,801,748
I recommend to use classes, because of that,
Class methods are non-enumerable.
A class definition sets of enumerable flag to false for all class member methods in the "prototype". That's good, because if we for..in over an object, we usually don't want it's class methods.
Classes have a default constructor() {}.
If there is no constructor in the class constructor, then an empty function is generated, same as if we had written constructor() {}.
Classes always use strict.
All code inside the class construct is automatically in strict mode.
Static Methods
We can also assign methods to the class function, not to its "prototype".
You can go further here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With