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 的绑定是永久的)。

相关推荐
PineappleCoder4 小时前
性能数据别再瞎轮询了!PerformanceObserver 异步捕获 LCP/CLS,不卡主线程
前端·性能优化
PineappleCoder4 小时前
告别字体闪烁 / 首屏卡顿!preload 让关键资源 “高优先级” 提前到
前端·性能优化
m0_471199634 小时前
【vue】通俗详解package-lock文件的作用
前端·javascript·vue.js
GIS之路5 小时前
GDAL 读取KML数据
前端
今天不要写bug5 小时前
vue项目基于vue-cropper实现图片裁剪与图片压缩
前端·javascript·vue.js·typescript
用户47949283569155 小时前
记住这张时间线图,你再也不会乱用 useEffect / useLayoutEffect
前端·react.js
咬人喵喵6 小时前
14 类圣诞核心 SVG 交互方案拆解(附案例 + 资源)
开发语言·前端·javascript
问君能有几多愁~6 小时前
C++ 日志实现
java·前端·c++
咬人喵喵6 小时前
CSS 盒子模型:万物皆是盒子
前端·css