前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 热点
旧版
首页程序员面试题库bind 与 call apply 区别
JavaScript函数与作用域

bind 和 call、apply 有什么区别?bind 返回的函数有什么特点?

call 和 apply 都是指定 this 马上调用函数,区别只在传参:call 一个个传,apply 传一个数组。bind 不调用,它返回一个新函数,this 和预先给的参数都被固定住,以后什么时候调都一样。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#函数与作用域
先看核心答案读代码示例
理解线索

一次性指定和永久固定

  1. callfn.call(obj, a, b),这一次调用用 obj 当 this
  2. applyfn.apply(obj, [a, b]),参数放在数组里传
  3. bindfn.bind(obj, a) 返回新函数,this 和 a 永久固定

每调用一次 bind 就得到一个全新的函数。事件监听用 bind 绑定后,解绑时必须传同一个引用,重新 bind 一次是解不掉的。

核心回答

先记住这个答案

三个方法都能指定函数执行时的 this。call 和 apply 是当场调用函数,区别只是参数写法:call(obj, a, b) 一个个传,apply(obj, [a, b]) 放进数组传。bind(obj, a) 不会调用函数,而是返回一个新函数,这个新函数的 this 永远是 obj,第一个参数永远是 a,调用时再传的参数排在后面。所以需要「现在就调」用 call 或 apply,需要「把函数交给别人以后再调」用 bind。

  • call 和 apply 立即执行,bind 返回新函数
  • call 逐个传参,apply 传数组
  • bind 之后 this 固定,再 bind 或 call 都改不了
  • 用 new 调用绑定函数时,this 换成新实例

三种写法放在一起比

同一个函数,分别用三种方式调用,再给 bind 预置一个参数。

执行时机和参数顺序JavaScript
function describe(prefix, suffix) {
  return prefix + this.name + suffix
}
const user = { name: 'Ada' }

console.log(describe.call(user, '[', ']')) // 逐个传参,立即执行
console.log(describe.apply(user, ['<', '>'])) // 数组传参,立即执行

const greet = describe.bind(user, 'Hi ') // 不执行,返回新函数
console.log(greet('!')) // 预置的 'Hi ' 在前,'!' 在后
console.log(greet.call({ name: 'Bob' }, '?')) // this 已固定,改不了
查看输出与解释
[Ada]
<Ada>
Hi Ada!
Hi Ada?

前两行在写下的那一刻就执行了。greet 是一个新函数,调用它时,bind 时给的 'Hi ' 排在第一个,调用时传的 '!' 排在后面。最后一行用 call 传了 Bob,但 this 早被 bind 固定成 user,所以还是 Ada。 apply 以前常用来把数组展开成参数,比如 Math.max.apply(null, arr)。有了展开语法以后,直接写 Math.max(...arr) 更清楚,apply 的出场机会少了很多。

bind 返回的函数有哪些特点

bind 返回的叫绑定函数,它内部记住了三样东西:原函数、固定的 this、预置的参数。调用它时,就用固定的 this 加上「预置参数 + 本次参数」去调原函数。

再 bind 一次也改不了 this
fn.bind(a).bind(b) 调用时,this 还是 a。第二次 bind 包的是第一个绑定函数,而第一个绑定函数调用原函数时,永远用 a,外面传什么 this 都不看。不过第二次 bind 预置的参数仍然有效,会接在第一次的参数后面。
用 new 调用时 this 会变
绑定函数被 new 调用时,bind 固定的 this 会被忽略,this 换成新创建的实例,预置参数照样生效。这是 new 的优先级高于 bind 的体现,也是手写 bind 时最容易漏掉的一点。另外,箭头函数本身没有 this,对它 bind 只有预置参数有用。
length 和 name 也会变
绑定函数的 length 等于原函数的 length 减去预置参数个数,最小是 0。name 会变成 bound describe 这样带 bound 前缀的名字,调试时看调用栈能认出来。
回答前,多想一步

容易答错的地方

解绑事件时又 bind 了一次
el.addEventListener('click', this.onClick.bind(this)) 之后,写 el.removeEventListener('click', this.onClick.bind(this)) 解不掉。每次 bind 返回的都是新函数,两个引用不相等。正确做法是先把 this.onClick.bind(this) 存到一个变量里,添加和移除都用它。
以为 bind 的优先级最高
普通调用、call、再 bind 都改不了绑定函数的 this,但 new 可以。只背「bind 优先级最高」会在追问 new 时答错。
以为 apply 的第二个参数必须是数组
它接受任何类数组对象,比如 arguments、{ length: 2, 0: 'a', 1: 'b' } 都行。传 null 或 undefined 表示不传参数。
试着用自己的话回答

面试官还会怎么问?

手写一个 bind 要注意什么?

核心是返回一个函数,里面用 apply 调原函数,参数是预置参数拼上调用时的参数。进阶要处理 new 的情况:判断 this instanceof 返回的函数,是的话用新实例当 this,并且让返回函数的 prototype 继承原函数的 prototype。

call 的第一个参数传 null 会怎样?

非严格模式下,this 会变成全局对象;严格模式下,this 就是 null。所以只想传参不关心 this 时传 null,要确认函数里没有用到 this。

性能上 call 和 apply 有区别吗?

apply 理论上多一步把类数组拆成参数列表,但现代引擎里这点差距可以忽略,按参数的形态选就行:手里已经是数组就用 apply 或展开语法,参数零散就用 call。

从一道题,走向一组知识

把知识连起来

函数与作用域

arguments 和函数的形参是一回事吗?改了一个另一个会变吗?

手写 bind 时要把预置参数和调用时的 arguments 拼在一起,得先弄清实参和形参的区别。

函数与作用域

函数默认参数是什么时候计算的?能用前面的参数当默认值吗?

绑定函数的 length 会减去预置参数个数,而原函数的 length 又受默认参数影响,两题放一起看更清楚。

放回知识体系中复习JavaScript 进阶知识

参考资料

  • Function.prototype.bind()

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

本题目录
  1. 先记住这个答案
  2. 三种写法放在一起比
  3. bind 返回的函数有哪些特点
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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