JavaScript_call_apply_bind
1. 核心区别
| 方法 | 调用时机 | 参数传递 | 返回值 |
|---|---|---|---|
call | 立即执行 | 参数列表 (thisArg, arg1, arg2, ...) | 函数执行结果 |
apply | 立即执行 | 参数数组 (thisArg, [arg1, arg2, ...]) | 函数执行结果 |
bind | 返回新函数,不立即执行 | 同 call(可预设参数) | 绑定了 this 的新函数 |
一句话总结:call / apply 是临时改变 this 并立即调用;bind 是永久绑定 this 并返回新函数,可延迟调用。
2. 手写实现
2.1 手写 call
javascript
Function.prototype.myCall = function(context, ...args) {
// 1. context 为 null/undefined 时指向全局对象(浏览器 window,Node global)
context = context || globalThis;
// 2. 用一个唯一 key 避免覆盖原对象属性
const fnKey = Symbol();
// 3. 将当前函数作为 context 的一个方法
context[fnKey] = this;
// 4. 执行函数并拿到结果
const result = context[fnKey](...args);
// 5. 删除临时属性
delete context[fnKey];
return result;
};2.2 手写 apply(仅参数处理不同)
javascript
Function.prototype.myApply = function(context, argsArray = []) {
context = context || globalThis;
const fnKey = Symbol();
context[fnKey] = this;
const result = context[fnKey](...argsArray);
delete context[fnKey];
return result;
};2.3 手写 bind(更复杂,需处理 new 和预设参数)
javascript
Function.prototype.myBind = function(context, ...boundArgs) {
const originalFn = this;
// 返回一个新函数
function boundFn(...callArgs) {
// 关键:如果通过 new 调用,this 指向实例,不应该绑定 context
const isNewCall = this instanceof boundFn;
const finalContext = isNewCall ? this : (context || globalThis);
return originalFn.call(finalContext, ...boundArgs, ...callArgs);
}
// 维护原型链(使得 boundFn 的实例能继承原函数原型)
if (originalFn.prototype) {
boundFn.prototype = Object.create(originalFn.prototype);
}
return boundFn;
};面试技巧:写 bind 时主动提到 new 优先级高于 bind 以及 原型链维护,能极大加分。
3. 实际使用场景
| 场景 | 示例 | 推荐方法 |
|---|---|---|
| 借用数组方法操作类数组 | [].slice.call(arguments) | call / apply |
| 取数组最大/最小值 | Math.max.apply(null, [1,2,3]) | apply |
| 继承(组合继承) | Parent.call(this, name) | call |
事件处理器中固定 this | this.handleClick.bind(this) | bind |
| 函数科里化(预设参数) | const add = (a,b)=>a+b; const add5 = add.bind(null,5); | bind |
防抖节流中保留 this | fn.apply(this, args) | apply |
技巧:结合自己项目中的一个真实案例说明,比如“用 bind 解决 React 类组件中事件回调的 this 丢失”。实际开发中,我常用 apply 处理类数组,用 bind 固定 React 事件回调的 this,用 call 实现继承。
4. 进阶考点
4.1 new 对 bind 的影响
问:“如果 bind 返回的函数被 new 调用,this 指向什么?”
答:指向新创建的实例,而不是 bind 传入的 context。因为 new 的优先级最高。
4.2 多次 bind 是否有效
javascript
function foo() { console.log(this.a); }
const obj1 = { a: 1 };
const obj2 = { a: 2 };
const bar = foo.bind(obj1).bind(obj2);
bar(); // 输出 1解释:bind 一旦绑定,其内部的 this 就不可再被覆盖(第二次 bind 无效)。因为第一次 bind 返回的新函数内部已经硬绑定了 obj1,再次 bind 只是包裹一层,但调用时实际执行的仍是第一次绑定的函数。