I would like to define two functions (or classes) in Javascript with the exact same function body, but have them be completely different objects. The use-case for this is that I have some common logic in the body which is polymorphic (the function can accept multiple types), but by only calling the function with a single type the function ends up faster, I assume since the JIT can take a happier fast path in each case.
One way of doing this is simply to repeat the function body entirely:
function func1(x) { /* some body */ }
function func2(x) { /* some body */ }
Another way of accomplishing the same thing with less repetition is eval()
:
function func(x) { /* some body */ }
function factory() { return eval("(" + func.toString() + ")") }
let func1 = factory(), func2 = factory()
The downside of eval()
of course being that any other tools (minifiers, optimisers, etc) are completely taken by surprise and have the potential to mangle my code so this doesn't work.
Are there any sensible ways of doing this within the bounds of a standard toolchain (I use Typescript, esbuild, and Vite), without using eval()
trickery or just copy-pasting the code? I also have the analagous question about class definitions.
Edit: to summarise what's been going on in the comments:
- Yes, the performance difference is real and measurable (especially on Chrome, less pronounced on Firefox and Safari), as demonstrated by this microbenchmark. The real program motivating this question is much larger and the performance differences are much more pronounced, I suspect because the JIT can do more inlining for monomorphic functions, which has many knock-on effects.
- The obvious solution of returning a closure does not work, i.e.
as demonstrated by this second microbenchmark. This is because a JIT will only compile a function body once, even if it is a closure.function factory() { function func() { /* some body */ } return func } let func1 = factory(), func2 = factory()
- It may be the case that this is already the best solution, at least when working within a standard JS/Typescript toolchain (which does not include code-generation or macro facilities).