使用 `call`, `apply`, `bind` 改变 JS 中 this 的指向

三葉Leaves Author

用法与区别

这三个函数可以被任意函数调用,也就是函数又调用了函数。

他们传入的第一个参数比较特殊,是传入一个对象之类的进去,这样调用他们三个的那个函数的内部语句的 this 环境就变成了你传进去的对象的环境了。

为了方便对比,我们用一个表格来清晰地展示它们的核心区别:

方法 作用 参数 返回值 执行时机
call() 调用函数,并指定 this thisArg, arg1, arg2, … (参数列表) 函数的执行结果 立即执行
apply() 调用函数,并指定 this thisArg, [arg1, arg2, ...] (参数数组) 函数的执行结果 立即执行
bind() 创建一个新函数,并永久绑定 this thisArg, arg1, arg2, … (参数列表) 一个绑定后的新函数 不立即执行
简单理解就是前两者,他们会得到函数的执行结果。比如
1
Math.max.apply(null, numbers)

就会得到 Math.max() 这个函数的执行结果。但是和直接执行这个函数的区别是:

  • 对于 call() ,它可以改变 this 的指向。看上面的表格,第一个参数不是 thisArg 吗?这玩意的作用是使得执行调用 call 的函数的时候,函数内部语句如果用到了 this ,这个 this 指向的就是你传的那个 thisArg。这在用于处理继承问题的时候,是一种非常干净优雅的方式(其他时候倒用的不多,还不如 apply)。

  • 对于 apply(),改变 this 指向的功能和上面一样,但是特殊点在于传入的参数是一个数组,再把数组里的东西作为参数传给调用 apply() 的函数。不过这玩意还真的想想就鸡肋,这不就是做了展开运算符做的事情吗?

  • 对于 bind(),改变 this 指向的功能和 call() 没两样,但是得到的是一个新的函数,而不是函数的结果。这个想想就明白了,是用来制作新函数的。

简单记忆法:

  • Call: 参数是 Comma-separated (逗号分隔)。
  • Apply: 参数是 Array (数组)。
  • Bind: Bound (绑定),返回一个绑定的函数,不立即执行。

巧妙用法:apply 配合 Math.max/min

Math.max()Math.min() 接受的是参数列表,而不是数组。apply 可以巧妙地将数组转换为参数列表。

  • 场景:获取数组中的最大/最小值
1
2
3
const numbers = [5, 2, 8, 1, 9];
const max = Math.max.apply(null, numbers); // this 在这里不重要,所以传入 null
console.log(max); // 9
  • 现代替代方案:扩展运算符 (...)
    扩展运算符同样可以做到,并且语法更优雅。
1
2
3
const numbers = [5, 2, 8, 1, 9];
const max = Math.max(...numbers);
console.log(max); // 9

这也是一个 apply 被现代语法替代的典型例子。

bind 的另一个用途:函数柯里化 (Partial Application)

bind 除了绑定 this,还可以预先设定函数的部分参数。

  • 场景:创建一个具有预设参数的新函数
1
2
3
4
5
6
7
8
9
function log(level, message) {
console.log(`[${level}] ${message}`);
}

// 创建一个专门用于记录错误的 log 函数
const logError = log.bind(null, 'ERROR'); // this 不重要,第一个参数是 'ERROR'

logError('Network request failed'); // 输出: [ERROR] Network request failed
logError('Invalid input'); // 输出: [ERROR] Invalid input

这种用法在创建功能更具体的工具函数时非常有用,至今仍在实践中使用。

总结

方法 核心功能 现代实践中的地位
call 立即执行,改变 this,传递参数列表 仍然用于方法借用,尤其是在一些底层库或需要兼容旧环境的代码中。日常业务中,其使用频率有所下降。
apply 立即执行,改变 this,传递参数数组 主要用于方法借用。在 Math.max 等场景下,已被更简洁的扩展运算符 (...) 替代。
bind 创建新函数,永久绑定 this 和部分参数 回调函数中固定 this 的场景,已基本被箭头函数 (=>) 全面取代。但在函数柯里化(预设参数) 方面,它依然是一个简洁实用的工具。

总而言之,call, apply, bind 仍然是每个 JS 开发者必须掌握的基础知识。但在现代前端开发中,由于 箭头函数扩展运算符 的出现,它们在某些最常见的场景下(如修复 this 指向、处理参数数组)已经有了更优雅、更推荐的替代方案。

  • 标题: 使用 `call`, `apply`, `bind` 改变 JS 中 this 的指向
  • 作者: 三葉Leaves
  • 创建于 : 2025-06-07 00:00:00
  • 更新于 : 2025-08-08 09:29:23
  • 链接: https://blog.oksanye.com/37686202c57f/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论