You've stepped into the trap that EricTboneJackson pointed out. By using sum inside a closure, write access to it is much slower. Because only one sum variable is shared across all your tests, this impacts all of them, despite not all of them requiring sum to be captured at all.
For comparison, I get these results on Node 12.2.0:
standard for x 2.99 ops/sec ±0.42% (12 runs sampled) for-of x 2.00 ops/sec ±0.50% (9 runs sampled) forEach x 1.11 ops/sec ±0.77% (7 runs sampled) reduce x 1.22 ops/sec ±0.28% (8 runs sampled) Fastest is standard for
Then after performing these modifications:
- capture sum only if necessary: remove the initial let sum declaration, then declare it inside the test itself (replace sum = 0 with let sum = 0)
- move the closure declarations inside the test where they're needed (only strictly necessary for adder, since sum isn't declared yet)
The results are much more drastic.
standard for x 32.70 ops/sec ±0.25% (56 runs sampled)
for-of x 8.21 ops/sec ±0.33% (25 runs sampled)
forEach x 1.00 ops/sec ±0.73% (7 runs sampled)
reduce x 1.22 ops/sec ±0.11% (8 runs sampled)
Fastest is standard for
So, the main take-away should be: Where performance is important, avoid unnecessary closures.