← 返回题目列表

call、apply、bind 有什么区别?它们如何改变 this?

高频 中等 第 11 / 29 题 更新于 2026/07/28
JavaScriptthiscallapplybind

简化版

callapply 会立即调用函数并指定 this,区别是参数传递形式不同;bind 不立即调用,而是返回一个 this 被绑定的新函数。它们本质上都是显式指定函数执行时的 this。

详细版

  • call 接收参数列表:fn.call(obj, a, b)。
  • apply 接收参数数组或类数组:fn.apply(obj, [a, b])。
  • bind 返回新函数:const g = fn.bind(obj, a),之后再调用。
  • 严格模式下 this 可以是传入的原始值或 undefined;非严格模式下 null/undefined 会指向全局对象。
  • bind 后的函数作为构造函数使用时,new 绑定优先级高于 bind 绑定的 this。

完整版教学

记忆钩子:call/apply 是“立刻借用方法”,bind 是“先借好,稍后再用”。

一、这题真正考什么

记忆钩子:call/apply 是“立刻借用方法”,bind 是“先借好,稍后再用”。

面试官想看的不是你能不能背一个术语,而是能不能解释 JavaScript 为什么会出现这些看似反直觉的结果。答题时要从执行模型、规范规则和工程边界三个角度展开。

二、底层机制怎么理解

JavaScript 函数的 this 不是由定义位置决定,而是由调用方式决定。call、apply、bind 提供了显式绑定 this 的能力,让一个函数可以在指定对象上下文中执行。它们常用于方法借用、函数柯里化、事件回调固定上下文和兼容旧代码。

JavaScript 高频题经常围绕“运行时如何决定结果”展开。只要能把创建阶段、调用方式、查找链路、转换规则或内存可达性说清楚,就能把题目从记忆题讲成原理题。

三、带数字或代码的小推演

Math.max.apply(null, [3, 7, 2]) 会把数组展开给 Math.max;handler.bind(vm) 可以把事件回调里的 this 固定到组件实例。若 bind 预置 2 个参数,后续调用再传 3 个参数,最终参数会按预置在前、调用在后的顺序合并。

下面把核心规则压成几行,复习时可以按顺序手推一遍:

fn.call(thisArg, arg1, arg2)
fn.apply(thisArg, [arg1, arg2])
const bound = fn.bind(thisArg, presetArg)
new bound() 时 this 指向新对象,而不是 thisArg

四、执行流程怎么走

可以把这道题放到下面的运行流程里看:

普通函数调用
   |
默认绑定/隐式绑定决定 this
   |
使用 call/apply
   |
立即以指定 this 执行
   |
使用 bind
   |
返回绑定 this 和预置参数的新函数

流程图的价值是把“现象”还原成“步骤”。面试追问通常就是换一段代码让你预测输出,按流程推比靠直觉猜更稳。

五、对比表格

方法是否立即执行参数形式
call参数逐个传
apply数组或类数组
bind返回新函数,可预置参数
箭头函数不适用普通 this 绑定this 来自外层词法环境

对比题要主动说适用场景和边界。JavaScript 的很多机制都不是“好或坏”,而是历史兼容、运行时灵活性和工程可维护性之间的折中。

六、工程实践和排查思路

  • 箭头函数没有自己的 this,call/apply/bind 不能改变它的 this。
  • bind 会返回新函数,removeEventListener 时必须保留同一个函数引用。
  • 遇到输出预测题时,不要只报结果,要按创建、查找、调用、转换、执行顺序解释。
  • 生产代码要优先选择可读性强、边界清晰的写法,把语言怪异点限制在工具函数或明确封装里。

七、常见误区与追问

  • 误区:call、apply、bind 只是参数写法不同。 要补上规范规则、执行阶段和反例,避免用一句经验话术盖过真正原因。
  • 误区:bind 后 this 永远不能被 new 改变。 要补上规范规则、执行阶段和反例,避免用一句经验话术盖过真正原因。
  • 误区:箭头函数也可以用 bind 改 this。 要补上规范规则、执行阶段和反例,避免用一句经验话术盖过真正原因。
  • 追问:bind 为什么可以实现函数柯里化? 先给规则,再用一小段代码或内存/调用示意解释为什么。
  • 追问:call/apply 在方法借用中怎么用? 先给规则,再用一小段代码或内存/调用示意解释为什么。
  • 追问:手写 bind 时为什么要处理 new? 先给规则,再用一小段代码或内存/调用示意解释为什么。

八、加强记忆

三者按“立即不立即、参数怎么传、this 优先级”记。call 逐个传,apply 数组传,bind 返回函数;箭头函数和 new 是两个必须单独说明的边界。

复习 JavaScript 基础题时,可以固定按“创建阶段、执行阶段、查找链路、调用方式、类型转换、工程边界”六步组织答案。这个框架能覆盖大多数输出题和原理题。