前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库call apply bind 区别与使用场景
JavaScript对象与原型

call、apply、bind 有什么区别?各自什么时候用?

三个方法都用来指定函数运行时的 this。call 和 apply 会立刻调用函数,call 把参数一个个传,apply 把参数放在一个数组里传。bind 不调用,它返回一个 this 被固定住的新函数,留着以后调用。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#对象与原型
先看核心答案读代码示例
理解线索

两个维度就能分清三个方法

  1. 什么时候执行call 和 apply 当场执行,bind 返回函数延后执行
  2. 参数怎么传call 和 bind 逐个传,apply 传一个数组
  3. 预设参数bind 除了 this 还能预先填好前几个参数

用 new 调用 bind 返回的函数时,绑定的 this 会被忽略,this 指向新创建的实例,但预设的参数仍然生效。

核心回答

先记住这个答案

call、apply、bind 都能指定函数执行时的 this。call(thisArg, a, b) 和 apply(thisArg, [a, b]) 会立即调用函数,只是传参方式不同,一个逐个传,一个传数组。bind(thisArg, a) 不会调用,而是返回一个新函数,这个新函数的 this 永远固定为 thisArg,前面的参数也可以预先填好。所以要马上执行用 call 或 apply,要把函数交给别人稍后调用(事件回调、定时器)用 bind。

  • call、apply 立即调用
  • call 逐个传参,apply 传数组或类数组
  • bind 后再 call 也改不了 this
  • 箭头函数没有自己的 this,三者都改不了它

一段代码对比三种写法

同一个 greet 函数,分别用三种方式指定 this。

立即调用与返回新函数JavaScript
const tom = { name: 'Tom' }
function greet(greeting, mark) {
  return greeting + ', ' + this.name + mark
}

console.log(greet.call(tom, 'Hi', '!')) // 参数逐个传
console.log(greet.apply(tom, ['Hello', '?'])) // 参数放数组里

const greetTom = greet.bind(tom, 'Hey') // 固定 this,并预设第一个参数
console.log(greetTom('~'))
console.log(greetTom.call({ name: 'Jerry' }, '.')) // 想再改 this,改不动
console.log(Math.max.apply(null, [3, 9, 5])) // apply 的经典用法:把数组摊开当参数
查看输出与解释
Hi, Tom!
Hello, Tom?
Hey, Tom~
Hey, Tom.
9

第四行最容易考:greetTom 已经被 bind 过,内部固定了 this 是 tom,再用 call 传 Jerry 也没用,打印的还是 Tom。同理,bind 连着调用两次,只有第一次生效。

各自最常见的使用场景

call 最常见的场景是借用别的对象的方法。比如 Object.prototype.toString.call(value) 用来判断类型,能拿到 '[object Array]' 这种精确结果;ES5 继承里写 Parent.call(this, name),让父构造函数在子类实例上初始化属性。

apply 适合参数本来就在数组里的情况。以前求数组最大值写 Math.max.apply(null, arr),现在用展开语法 Math.max(...arr) 更直观,所以 apply 在新代码里出现得越来越少。

bind 用在「函数要交出去,但 this 不能丢」的场景。比如把对象方法传给 addEventListener 或 setTimeout,如果直接传 obj.method,调用时 this 就不再是 obj 了。写成 obj.method.bind(obj) 就能锁住。React 类组件在构造函数里写 this.handleClick = this.handleClick.bind(this) 就是这个原因。

为什么方法传出去会丢 this

普通函数的 this 不是定义时决定的,而是调用时看「点号前面是谁」。obj.method() 调用,this 是 obj;把 obj.method 赋给变量 fn 再调用 fn(),点号前面什么都没有,非严格模式下 this 是全局对象,严格模式下是 undefined。

bind 返回的函数内部记住了目标 this,每次调用都用它去执行原函数,所以不管以后怎么调用都不会变。箭头函数则是另一个思路:它根本没有自己的 this,用的是定义时外层的 this,所以 call、apply、bind 对它都无效。

回答前,多想一步

容易答错的地方

以为 bind 会立即执行函数
bind 只返回新函数。button.onclick = handler.bind(obj) 是对的,写成 handler.bind(obj)() 就等于 handler.call(obj),当场就执行了。
以为 bind 过的函数还能再改 this
call、apply、再次 bind 都改不了。唯一的例外是用 new 调用,这时 this 指向新实例,绑定的 this 被忽略。
第一个参数传 null 就等于没传
非严格模式下,传 null 或 undefined 时 this 会变成全局对象,传原始值会被包装成对象。严格模式下传什么就是什么,null 就是 null。
试着用自己的话回答

面试官还会怎么问?

手写一个 call 的思路是什么?

把函数临时挂到目标对象上,用「对象.方法()」的方式调用,这样 this 自然就是这个对象,调用完再删掉。为了避免和已有属性重名,临时属性名用 Symbol()。thisArg 为 null 时退回全局对象,原始值用 Object() 包装一下。

bind 返回的函数 length 和 name 是什么?

name 是 'bound ' 加原函数名,比如 'bound greet'。length 是原函数形参个数减去预设参数个数,最小为 0,上面的 greetTom.length 是 1。

类数组对象怎么用数组方法?

用 call 借用,比如 Array.prototype.map.call(nodeList, fn)。数组方法只要求 this 有 length 和数字索引,不要求真的是数组。现在更常用 Array.from(nodeList) 或展开语法先转成数组。

从一道题,走向一组知识

把知识连起来

对象与原型

Object.getPrototypeOf 和 Object.setPrototypeOf 现在还该用吗?

Array.prototype.slice.call(arguments) 这类借用写法,本质是调用原型上的方法,可以顺带理解原型的读取和修改。

对象与原型

class 里的 getter/setter 和普通方法有什么区别?和描述符里的 get/set 是一回事吗?

getter 里的 this 也是调用时决定的,通过实例访问就指向实例,和 call 改 this 是同一套规则。

参考资料

  • JavaScript:对象与原型参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 一段代码对比三种写法
  3. 各自最常见的使用场景
  4. 为什么方法传出去会丢 this
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑