[英]Why javascript call method fails to execute on array prototype method
我正在玩 JS 功能以提高我對語言的理解。
在下面的示例中,我嘗試使用call
方法在給定數組 object 上啟動數組 function。我知道完成工作的替代方案; 但是,我很好奇為什么我編寫的代碼不起作用?。
謝謝!
代碼
const f_timeit = (f) => {
return function(...args) {
util.p(`Entering function ${f.name}`);
const start_time = Date.now();
try {
return f(...args);
} finally {
util.p(`Exiting ${f.name} after ${Date.now() - start_time}ms`);
}
}
};
const rarr = [...Array(10000000)].map(e => ~~(Math.random() * 20));
// following works
console.log(f_timeit((arr) => {
return arr.reduce((acc, val) => acc + val, 0);
})(rarr));
// following fails
util.p(f_timeit(Array.prototype.reduce.call)(rarr, (acc, val) => acc + val, 0));
錯誤:
return f(...args);
^
TypeError: f is not a function
錯誤消息有點誤導,不是說“ f
不是函數”,而是f
是Function.prototype.call
方法,該方法在不是 function 的對象上調用 - 特別是undefined
。 這是由於this
參數的工作原理,特別是因為訪問 object 上的方法不會自動綁定它們。
所以實現你想要的各種方法是
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)
但是,我通常建議您更改f_timeit
以尊重調用返回的 function 時傳遞的this
值:
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`);
}
}
};
這樣,您可以使用
f_timeit(Array.prototype.reduce).call(rarr, (acc, val) => acc + val, 0)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.