Is it better using variables which define a function or using a function in the first place? Furthermore, is there a difference for tree-shaking?
I have a lot of calculation (static) intensive helper classes and was wondering what the best (memory/speed) is.
Here the different ways I have in mind:
class MyClass {
readonly functionA = (v: string | number, maxDeep: number, curDeep: number = 0): string => {
if (curDeep < maxDeep) {
return this.functionA(v, maxDeep, curDeep + 1);
} else {
return "function A" + v;
}
}
static functionB(v: string | number, maxDeep: number, curDeep: number = 0): string {
if (curDeep < maxDeep) {
return MyClass.functionB(v, maxDeep, curDeep + 1);
} else {
return "function B" + v;
}
}
functionC(v: string | number, maxDeep: number, curDeep: number = 0): string {
if (curDeep < maxDeep) {
return this.functionC(v, maxDeep, curDeep + 1);
} else {
return "function C" + v;
}
}
static readonly functionD = (v: string | number, maxDeep: number, curDeep: number = 0): string => {
if (curDeep < maxDeep) {
return MyClass.functionD(v, maxDeep, curDeep + 1);
} else {
return "function D" + v;
}
}
}
I tried using JSBen for measuring a difference but the results seem to be random.
If you are that concerned about performance to optimize at this level, then having a class that only has static methods introduces some totally unnecessary overhead. Classes are designed to be instantiated, and if you don't use that feature you are wasting some computational resources to have those features available.
When I run your examples (MacOS, Chrome 90.0.4430.93) I get this:
What's clear is that static methods have a large performance costs. Where instance methods are guaranteed to be fast. I wish I could tell you why, but I'm sure it has something to do with the fact that classes are design to be instantiated.
Much simpler than that, is a simple object. Let's add these two tests:
Those run just about as fast as the instance methods. And it's a pattern that makes more sense. There's no classes because there is no instantiation.
But there's an even simpler alternative:
Performance wise, we have a winner here. I'm fairly sure this is because you never have to look up a property on an object. You have a reference to the function directly, and can execute it without asking any other object where to find it first.
Updated jsben.ch
And as far as tree shaking, this form is by far the best. It's easiest for bundlers to manage whole exported values, rather than trying to slice and dice individual objects.
If you do something like:
Then it's super easy for a bundler to see that
myFuncB
is never imported or referenced, and could be potentially pruned.Lastly...
It's very unlikely for performance optimizations of this level to matter in the vast majority of javascript applications. So use the data structures that make the most sense for the application, and according to the standards of the codebase/organization. Those things matter so much more.