JavaScript 中 call、apply、bind 的区别

先理解核心:它们都是干啥的?

想象你借了一本书(函数),但你想让别人(指定对象)来读这本书的某个章节(执行函数)。

  • call:现在就让人读,你一个个告诉他读哪几页

  • apply:现在就让人读,你把页数写在一张纸条上交给他

  • bind:不急着读,先告诉他要读哪几页,给他一张"读书券",以后随时可以让他读


我的"顿悟三连"

第一层困惑:它们好像都一样?

刚学的时候,看代码:

javascript 复制代码
fn.call(obj, 1, 2, 3)
fn.apply(obj, [1, 2, 3])
fn.bind(obj, 1, 2, 3)()

内心OS:不就是参数写法不一样吗?搞这么复杂干嘛!

第二层顿悟:原来是"立即执行"和"稍后执行"的区别

直到有一次写事件监听:

javascript 复制代码
// 错误示范 ❌
button.onclick = user.sayHello.call(user);  
// 页面加载完立刻就执行了!不是我想要的

// 正确示范 ✅
button.onclick = user.sayHello.bind(user);
// 点击时才执行,完美!

这一刻我懂了:bind 是"发号施令"但不立即行动,call/apply 是"立刻执行"。

第三层顿悟:什么时候用 call,什么时候用 apply?

有次写代码找数组最大值:

javascript

javascript 复制代码
// 用 apply 多优雅
Math.max.apply(null, [1, 2, 3, 4, 5]);

// 用 call 就尴尬了
Math.max.call(null, 1, 2, 3, 4, 5); // 也行,但参数多时累死

这一刻我悟了:

  • 已有数组 → apply(直接把数组扔进去)

  • 参数明确 → call(看得清楚,不用转数组)


终极对比表(我背了这一张就够了)

维度 call apply bind
执行时机 立即执行 立即执行 返回新函数,不执行
参数形式 逐个传入 a,b,c 数组传入 [a,b,c] 逐个传入,可分批传
返回值 函数结果 函数结果 新函数
经典场景 继承父类属性 找数组最大/小值 事件绑定、setTimeout
记忆口诀 C all = Comma(逗号) A pply = Array(数组) B ind = Back(稍后)

面试官最爱问的"坑"

Q:bind 之后还能改 this 吗?

javascript 复制代码
const obj = { name: 'obj' };
const obj2 = { name: 'obj2' };

function test() { console.log(this.name); }

const bound = test.bind(obj);
bound(); // 'obj'
bound.call(obj2); // 还是 'obj'!bind 绑定了就改不了了

Q:箭头函数能用 call/apply/bind 吗?

javascript 复制代码
const arrow = () => { console.log(this); };

// 没用!箭头函数的 this 是定义时就定死的
arrow.call({ name: 'test' }); // this 还是原来的

Q:手写一个 bind 看看?

javascript 复制代码
Function.prototype.myBind = function(context, ...bindArgs) {
  const fn = this;
  return function(...callArgs) {
    return fn.apply(context, [...bindArgs, ...callArgs]);
  };
};

我的最终心得

不要死记硬背,要理解设计意图:

  • call:适合参数数量固定,想写得直观时

  • apply:适合参数已经在数组里,或者数量不确定时

  • bind:适合不急着执行,或者要传给事件监听、定时器时

最常用的反而是 apply (处理数组)和 bind(处理 this 指向),call 用得最少。但面试爱问区别,所以三个都得懂。

相关推荐
weixin_4604435613 小时前
2026年新修订《网络安全法》实施:Java私有化考试系统如何做好SBOM、漏洞治理与安全升级?
java·开发语言·在线考试系统·企业培训考试系统·宏远培训考试系统·国企培训考试系统·国产化培训系统
子兮曰14 小时前
把 649 种文件格式塞进一个网页里:一个「文件不出浏览器」的预览器
前端·javascript·后端
Cc.Y16 小时前
Java零基础入门:可变字符串与包装类:StringBuilder、StringBuffer 与 通讯录管理系统实战
java·开发语言·python
paopaokaka_luck16 小时前
基于springboot+vue的智慧家政管理系统(AI问答、 WebSocket实时沟通、ECharts运营分析、订单规则与服务追踪)
java·javascript·spring boot·数据分析·echarts·mybatis
sm_9267870517 小时前
RFID 标签打印的技术实现要点与二次开发实践
java·大数据·前端·c++·编辑器
阿森_dev17 小时前
2027 届毕设选题怎么选:30 个 Java 方向选题的实现难度排序
java·开发语言·spring boot·毕业设计·课程设计
by2099917 小时前
C++ 多态:同一个基类接口,调用不同的函数
开发语言·c++·经验分享·多态
笔墨登场说说17 小时前
flink bin/start-cluster.sh 帮我做成开机启动
开发语言·python
Sarvartha17 小时前
Lambda 表达式和函数式接口
java·开发语言
IMPYLH17 小时前
HTML 的 <video> 元素
前端·html