The error message is a bit misleading, it's not that "f is not a function" but rather that f is the Function.prototype.call method that was invoked on something that is not a function - in particular undefined. This is due to how the this argument works, and in particular because accessing methods on an object does not automatically bind them.
So various ways to achieve what you want are
f_timeit(() => rarr.reduce((acc, val) => acc + val, 0))()
f_timeit((ctx) => ctx.reduce((acc, val) => acc + val, 0))(rarr)
f_timeit((ctx, reducer) => ctx.reduce(reducer, 0))(rarr, (acc, val) => acc + val)
f_timeit((ctx, reducer, init) => ctx.reduce(reducer, init))(rarr, (acc, val) => acc + val, 0)
f_timeit((ctx, ...args) => ctx.reduce(...args))(rarr, (acc, val) => acc + val, 0)
f_timeit((ctx, ...args) => Array.prototype.reduce.apply(ctx, args))(rarr, (acc, val) => acc + val, 0)
f_timeit((ctx, ...args) => Array.prototype.reduce.call(ctx, ...args))(rarr, (acc, val) => acc + val, 0)
f_timeit((...args) => Array.prototype.reduce.call(...args))(rarr, (acc, val) => acc + val, 0)
// f_timeit(Array.prototype.reduce.call)(rarr, (acc, val) => acc + val, 0) - no!
f_timeit(Array.prototype.reduce.call.bind(Array.prototype.reduce))(rarr, (acc, val) => acc + val, 0) // yes!
f_timeit(Function.prototype.call.bind(Array.prototype.reduce))(rarr, (acc, val) => acc + val, 0)
However, I would generally recommend that you change f_timeit to respect the this value passed when the returned function is called:
const f_timeit = (f) => {
return function(...args) {
util.p(`Entering function ${f.name}`);
const start_time = Date.now();
try {
return f.call(this, ...args);
// ^^^^
return f.apply(this, args); // or equivalently
} finally {
util.p(`Exiting ${f.name} after ${Date.now() - start_time}ms`);
}
}
};
That way, you can use
f_timeit(Array.prototype.reduce).call(rarr, (acc, val) => acc + val, 0)
callmethod is not bound to thereducefunction. You may as well have usedf_timeit(Function.prototype.call), same thing. The error message is very misleading btw, it's not thatfis not a function but rather thatcallwas invoked on something that is not a function.call.bind(reduce). Another (better) solution is to usef.apply(this, args)inf_timeit, thenf_timeit(Array.prototype.reduce).call(rarr, …, 0).f_timeit(Array.prototype.reduce).call(rarr, (acc, val) => acc + val, 0)