核心区别
| 方法 | 执行时机 | 参数形式 | 返回值 | 典型场景 |
|---|---|---|---|---|
bind | 延迟执行 | 逐个参数 | 新绑定函数 | 回调函数绑定上下文 |
call | 立即执行 | 参数列表 | 原函数返回值 | 明确参数数量的调用 |
apply | 立即执行 | 数组/类数组 | 原函数返回值 | 动态参数数量的调用 |
方法详解
1. bind
语法
const boundFn = originalFn.bind(thisArg, arg1, arg2, ...)
特性
- 不立即执行:返回一个绑定了
this的新函数 - 参数预置:支持提前固定部分参数
- 不可覆盖:新函数的
this无法被二次修改
示例
const user = { name: "John" };
function showMessage(text) {
console.log(`${text}, ${this.name}!`);
}
const boundShow = showMessage.bind(user, "Hello");
boundShow(); // "Hello, John!"
2. call
语法
const result = originalFn.call(thisArg, arg1, arg2, ...)
特性
- 立即执行:直接调用原函数
- 参数逐个传递:适合已知参数数量的场景
- 灵活性强:常用于借用对象方法
示例
const calculator = {
sum(a, b) {
return a + b;
}
};
function multiply(c) {
return this.sum(2, 3) * c;
}
console.log(multiply.call(calculator, 5)); // (2+3)*5 = 25
3. apply
语法
const result = originalFn.apply(thisArg, [arg1, arg2, ...])
特性
- 立即执行:与
call相同 - 数组传参:适合动态参数场景
- 性能优化:某些引擎对数组参数有优化
示例
Math.max.apply(null, [1, 5, 3]); // 5
Array.prototype.push.apply(arr1, arr2); // 合并数组
手写实现
实现 bind
Function.prototype.myBind = function(context, ...args) {
const self = this;
return function(...innerArgs) {
return self.apply(context, args.concat(innerArgs));
};
};
// 测试
const boundFn = sum.myBind({}, 2);
console.log(boundFn(3)); // 5 (当 sum = (a,b) => a+b 时)
实现 call
Function.prototype.myCall = function(context, ...args) {
context = context || globalThis; // 浏览器环境用 window
const key = Symbol('tempFn');
context[key] = this;
const result = context[key](...args);
delete context[key];
return result;
};
// 测试
function test(a) { return this.x + a }
console.log(test.myCall({x:10}, 5)); // 15
实现 apply
Function.prototype.myApply = function(context, argsArray = []) {
context = context || globalThis;
const key = Symbol('tempFn');
context[key] = this;
const result = context[key](...argsArray);
delete context[key];
return result;
};
// 测试
function test(a, b) { return this.x + a + b }
console.log(test.myApply({x:10}, [2, 3])); // 15
总结
-
选择原则:
- 需要函数延迟执行 →
bind - 立即调用且参数确定 →
call - 立即调用且参数动态 →
apply
- 需要函数延迟执行 →
-
底层原理:
- 本质上都是通过隐式绑定
this实现 - 现代引擎对这三个方法有深度优化
- 本质上都是通过隐式绑定
-
进阶技巧:
- 使用
bind实现函数柯里化 - 通过
apply实现数组合并等操作 - 使用
call实现伪数组转换(如Array.prototype.slice.call(arguments))
- 使用
掌握这三个方法,能显著提升对 JavaScript 执行上下文的理解与控制能力!