Appearance
2804. call vs apply vs bind
Problem: 2804. 数组原型的 forEach 方法
js
/**
* apply
*/
Array.prototype.forEach = function (callback, context) {
const values = this;
for (let i = 0; i < values.length; i++) {
callback.apply(context, [values[i], i, values])
}
}
/**
* call
*/
Array.prototype.forEach = function (callback, context) {
const values = this;
for (let i = 0; i < values.length; i++) {
callback.call(context, values[i], i, values)
}
}
/**
* bind - 参数可以预绑定
*/
Array.prototype.forEach = function (callback, context) {
const values = this;
for (let i = 0; i < values.length; i++) {
callback.bind(context, values[i], i, values)();
}
}三者唯一的本质区别
| 方法 | 是否立即执行 | 传参方式 |
|---|---|---|
| call | 是 | 逗号分隔 |
| apply | 是 | 数组 |
| bind | 否 | 逗号分隔(可分批) |
call 和 apply 的区别主要在传参格式:call(ctx, a, b, c) vs apply(ctx, [a, b, c])。选择哪个,通常取决于参数当前的自然形态。
bind 与前两者的本质区别在于:不执行函数,返回一个新函数。这个新函数可以在之后任意时机调用,this 和部分参数已被锁定。
在 forEach 中的应用
以 forEach 为例,三者都能实现回调的 this 绑定:
call最直接,逐个传参,可读性最好apply需要把参数包成数组,多一次数组创建bind做了两次函数调用(bind 一次 + 执行一次),在循环中开销最大
在这类 forEach polyfill 里,call 往往是更直接的选择。bind 在循环中会额外创建函数对象,除非确实需要延迟执行,否则没有明显收益。
call/apply vs 现代写法
ES6 之后,扩展运算符让 apply 的使用场景大幅减少:fn.apply(ctx, arr) 等价于 fn.call(ctx, ...arr)。现代代码更倾向于 call + 扩展运算符,因为意图更明确(不是在「应用数组」,而是在「展开数组传参」)。
