JavaScript call、apply、bind 方法解析

JavaScript call、apply、bind 方法解析

在 JavaScript 中,callapplybind 都是用来**this** 改变函数执行时 指向 的核心方法,它们的核心目标一致,但使用方式、执行时机和传参形式有明显区别。

js 复制代码
const dog = {
  name: "旺财",
  sayName() {
    console.log(this.name);
  },
  eat(food) {
    console.log(`${this.name} 在吃${food}`);
  },
  eats(food1, food2) {
    console.log(`${this.name} 在吃${food1}和${food2}`);
  },
};

const cat = {
  name: "咪咪",
};
// call 会立即执行函数,并且改变 this 指向
dog.sayName.call(cat); // 输出 '咪咪'
dog.eat.call(cat, "🐟"); // 输出 '咪咪 在吃🐟'

dog.sayName.apply(cat); // 输出 '咪咪'

dog.eats.call(cat, "🐟", "🐔"); // 输出 '咪咪 在吃🐟和🐔'

dog.eats.apply(cat, ["🐟", "🐔"]); // 输出 '咪咪 在吃🐟和🐔'

const boundEats = dog.eats.bind(cat);
boundEats("🐟", "🐔"); // 输出 '咪咪 在吃🐟和🐔'

一、核心共性

三者的核心作用:this 手动指定函数执行时的 指向 ,突破函数默认的 this 绑定规则(比如对象方法的 this 原本指向对象本身,通过这三个方法可以强制指向其他对象)。

以示例中的 dog.sayName() 为例,默认执行时 this 指向 dog,但通过 call/apply/bind 可以让 this 指向 cat,从而输出 咪咪 而非 旺财

二、逐个解析

1. call

  • 执行时机立即执行 函数

  • 传参方式 :第一个参数是 this 要指向的目标对象,后续参数逐个单独传递(逗号分隔)

  • 语法函数.call(thisArg, arg1, arg2, ...)

示例解析:
js 复制代码
// this 指向 cat,无额外参数,立即执行 sayName
dog.sayName.call(cat); // 输出 '咪咪'

// this 指向 cat,额外参数 '🐟' 逐个传递,立即执行 eat
dog.eat.call(cat, "🐟"); // 输出 '咪咪 在吃🐟'

// 多参数场景:参数逐个传递,立即执行 eats
dog.eats.call(cat, "🐟", "🐔"); // 输出 '咪咪 在吃🐟和🐔'

2. apply

  • 执行时机立即执行 函数(和 call 一致)

  • 传参方式 :第一个参数是 this 要指向的目标对象,后续参数必须放在一个数组(或类数组)中传递

  • 语法函数.apply(thisArg, [arg1, arg2, ...])

示例解析:
js 复制代码
// 无额外参数,数组可以为空(或不传),立即执行 sayName
dog.sayName.apply(cat); // 输出 '咪咪'

// 多参数场景:参数放在数组中传递,立即执行 eats
dog.eats.apply(cat, ["🐟", "🐔"]); // 输出 '咪咪 在吃🐟和🐔'

注意:apply 适合参数数量不固定、或参数已存在于数组中的场景(比如 Math.max.apply(null, [1,2,3]) 求数组最大值)。

3. bind

  • 执行时机不立即执行 函数,而是返回一个绑定了新 this 指向的新函数,后续需要手动调用这个新函数才会执行

  • 传参方式 :第一个参数是 this 要指向的目标对象,后续参数可以提前绑定(柯里化),也可以在调用新函数时补充

  • 语法const 新函数 = 函数.bind(thisArg, arg1, arg2, ...); 新函数(剩余参数);

示例解析:
js 复制代码
// 第一步:bind 不执行,仅绑定 this 为 cat,返回新函数 boundEats(原变量名 boundSayName 已修改)
const boundEats = dog.eats.bind(cat);

// 第二步:手动调用新函数,传递参数 '🐟' 和 '🐔',此时才执行 eats
boundEats("🐟", "🐔"); // 输出 '咪咪 在吃🐟和🐔'
进阶用法:
js 复制代码
// 提前绑定部分参数(柯里化),this 仍指向 cat
const boundEatWithFish = dog.eats.bind(cat, "🐟");
// 调用时补充剩余参数,同样输出目标结果
boundEatWithFish("🐔"); // 输出 '咪咪 在吃🐟和🐔'

三、核心区别总结

特性 call apply bind
执行时机 立即执行 立即执行 不立即执行,返回新函数
传参形式 逐个传递(逗号分隔) 数组/类数组传递 可提前绑定,也可调用时传
返回值 函数执行结果 函数执行结果 绑定 this 后的新函数

四、常见使用场景

  1. call :适用于参数数量明确、需要立即执行的场景(比如继承:Parent.call(this, arg1));

  2. apply :适用于参数是数组/类数组的场景(比如求数组最大值:Math.max.apply(null, arr));

  3. bind :适用于需要延迟执行、或需要重复使用绑定 this 后的函数的场景(比如事件回调、定时器:btn.onclick = fn.bind(obj))。

五、补充注意点

  • 如果第一个参数传 null/undefined,在非严格模式下,this 会指向全局对象(浏览器中是 window,Node 中是 global);严格模式下 thisnull/undefined

  • bind 返回的新函数不能通过 call/apply 再次修改 this 指向(bind 的绑定是永久的)。

相关推荐
程序员黑豆3 小时前
Java类型推断完全指南:从var到菱形运算符,掌握使用限制与最佳实践
java·前端·ai编程
To_OC4 小时前
踩了个 TS 的坑之后,我终于把 type 和 interface 掰明白了
前端·react.js·typescript
GreenTea4 小时前
深度解读 Anthropic 多智能体报告:更强的模型 ≠ 更好的协调
前端·后端·算法
浮生望4 小时前
前端API工程化:用 Mock 数据与 Axios 配置实现独立于后端的并行开发
前端
2603_965148114 小时前
如何解析JSON数据?API返回的商品信息处理教程
开发语言·数据库·python·自动化·json·api
万少5 小时前
给 DeepSeek Harness 装个"应用商店":一条命令,595 个插件随你逛
前端·javascript·后端
波波0075 小时前
C# 15 重磅新特性: 带标签 break 与 continue:重新定义嵌套循环控制流
服务器·前端·c#
Brown.alexis6 小时前
es6知识点1-自备使用
前端·ecmascript·es6
小爬的老粉丝7 小时前
JavaScript 纯前端预览 WPS:先识别容器,再路由解析器
前端·javascript·wps
知无不研7 小时前
lambda表达式的使用(3)
开发语言·c++·lambda