为何JavaScript中call方法调用Array原型方法失败?
问题:为什么用
f_timeit(Array.prototype.reduce.call)会报错? 我正在研究JavaScript特性以加深对该语言的理解。在以下示例中,我尝试使用call方法调用数组对象的Array.prototype.reduce方法,我知道其他实现方式,但好奇为何这段代码无法运行?
代码
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)); // 这段可以正常运行 console.log(f_timeit((arr) => { return arr.reduce((acc, val) => acc + val, 0); })(rarr)); // 这段运行失败 util.p(f_timeit(Array.prototype.reduce.call)(rarr, (acc, val) => acc + val, 0));
错误信息
return f(...args); ^ TypeError: f 不是一个函数
原因分析
Array.prototype.reduce.call并不是一个独立可直接调用的函数——它本质是Function.prototype.call方法的引用,但这个引用脱离了原本的上下文(也就是reduce方法)。当你把call作为参数传给f_timeit时,它只是一个普通函数,不再和reduce绑定。
当f_timeit内部执行f(...args)时,相当于直接调用call(...args),但call方法必须依赖它的this指向(也就是目标函数reduce)才能正常工作。此时this默认指向全局对象(严格模式下为undefined),导致call无法找到要执行的目标函数,最终抛出“不是函数”的错误。
解决方法
方法1:用箭头函数包装上下文
用箭头函数包裹Array.prototype.reduce.call,确保调用时上下文正确:
util.p(f_timeit((arr, accFn, init) => { return Array.prototype.reduce.call(arr, accFn, init); })(rarr, (acc, val) => acc + val, 0));
方法2:通过bind绑定上下文
使用bind把call的this固定为reduce方法,生成一个带绑定上下文的新函数:
util.p(f_timeit(Function.prototype.call.bind(Array.prototype.reduce))(rarr, (acc, val) => acc + val, 0));
内容的提问来源于stack exchange,提问作者Validus Oculus
相关产品推荐
相关产品推荐

