在 JavaScript 中,call、apply 和 bind 的核心作用都是改变函数内部的 this 指向。为了让你生动形象地理解,我们可以用**"借钱"**的场景来打个比方:
call= "打电话借钱":立刻打过去,参数一个一个说,马上借到钱(立即执行)。apply= "申请借钱":立刻提交申请,但参数打包成一张清单(数组)一次性给过去,马上借到钱(立即执行)。bind= "绑定借钱协议":不立刻借钱,而是签一份协议,以后随时可以拿着这份协议去借钱(返回新函数,延迟执行)。
下面我们用一段生动的 JS 代码来具体演示:
1. call:立即执行,参数逐个传递
就像你给朋友打电话,把借钱的理由和金额一个一个说清楚。
function borrowMoney(reason, amount) {
console.log(`我是${this.name},因为${reason},想借${amount}元`);
}
const person = { name: "张三" };
// 立即执行,参数用逗号隔开,逐个传递
borrowMoney.call(person, "交房租", 2000);
// 输出:我是张三,因为交房租,想借2000元
2. apply:立即执行,参数数组传递
就像你填了一张借款申请表,把理由和金额写在表里,一次性提交。
// 同样的函数和对象
const person = { name: "李四" };
// 立即执行,参数打包成一个数组传递
borrowMoney.apply(person, ["买电脑", 8000]);
// 输出:我是李四,因为买电脑,想借8000元
💡 适用场景:当你手里刚好有一个数组(比如 Math.max.apply(null, [1, 2, 3]) 求最大值),用 apply 最方便。
3. bind:不立即执行,返回新函数
就像你签了一份"随时可以借钱"的协议,现在不借钱,等以后需要的时候再调用。
const person = { name: "王五" };
// 不会立即执行!而是返回一个绑定了 this 的新函数
const borrowLater = borrowMoney.bind(person, "结婚");
// 稍后执行,只需要补充剩下的参数
borrowLater(50000);
// 输出:我是王五,因为结婚,想借50000元
💡 适用场景:在事件监听(如 button.addEventListener('click', this.handleClick.bind(this)))或定时器中,防止 this 丢失。
📊 核心区别一览表
| 方法 | 执行时机 | 参数传递方式 | 返回值 | 记忆口诀 |
|---|---|---|---|---|
call |
立即执行 | 逐个传递 (arg1, arg2) |
函数的执行结果 | 打电话借钱,一个一个说 |
apply |
立即执行 | 数组传递 ([arg1, arg2]) |
函数的执行结果 | 申请借钱,一次性给清单 |
bind |
延迟执行 | 逐个传递(可部分传参) | 绑定后的新函数 | 绑定借钱,以后随时要 |
通过这种"借钱"的比喻,再结合代码中参数传递的形式(逗号分隔 vs 数组)以及是否立即执行,你就能非常清晰地记住它们的区别了!