call、bind、apply

127 阅读2分钟

在 JavaScript 中,callbind 和 apply 是 Function 对象自带的三个重要方法,用于改变函数的 this 指向,实现函数的灵活调用。它们的核心区别在于 调用方式 和 参数传递形式

1. call 方法

语法

function.call(thisArg, arg1, arg2, ...)

特点

  • 立即执行 函数,并指定函数内部的 this 指向为 thisArg
  • 参数列表:后续参数 arg1, arg2, ... 会作为原函数的参数传入。

示例

const person = { name: 'Alice' };

function greet(message) {
  console.log(`${message}, ${this.name}`);
}

greet.call(person, 'Hello'); // 输出: "Hello, Alice"

2. apply 方法

语法

function.apply(thisArg, [argsArray])

特点

  • 立即执行 函数,并指定函数内部的 this 指向为 thisArg
  • 参数数组:第二个参数必须是 数组或类数组对象,数组元素会被展开作为原函数的参数。

示例

const numbers = [5, 6, 2, 3, 7];

// 求数组中的最大值
const max = Math.max.apply(null, numbers);
console.log(max); // 输出: 7

3. bind 方法

语法

const newFunc = function.bind(thisArg, arg1, arg2, ...)

特点

  • 不立即执行:返回一个 新函数,新函数的 this 被永久绑定为 thisArg
  • 预设参数:后续参数 arg1, arg2, ... 会被预设到新函数中。

示例

const module = {
  x: 42,
  getX: function() {
    return this.x;
  }
};

const unboundGetX = module.getX;
console.log(unboundGetX()); // 输出: undefined (this 指向全局对象)

const boundGetX = unboundGetX.bind(module);
console.log(boundGetX()); // 输出: 42 (this 被绑定为 module)

核心区别对比表

方法是否立即执行this 绑定方式参数传递形式典型应用场景
call✅ 立即执行临时绑定参数列表 arg1, arg2函数复用、继承场景
apply✅ 立即执行临时绑定数组 [arg1, arg2]与数组相关的操作(如 Math.max
bind❌ 返回新函数永久绑定(硬绑定)预设参数回调函数、事件处理程序保持上下文

典型应用场景

1. 函数复用

function greet(message) {
  return `${message}, ${this.name}`;
}

const alice = { name: 'Alice' };
const bob = { name: 'Bob' };

console.log(greet.call(alice, 'Hi')); // "Hi, Alice"
console.log(greet.call(bob, 'Hello')); // "Hello, Bob"

2. 继承(模拟子类调用父类构造函数)

function Animal(name) {
  this.name = name;
}

function Dog(name, breed) {
  // 调用 Animal 构造函数,绑定 this 为 Dog 实例
  Animal.call(this, name);
  this.breed = breed;
}

const myDog = new Dog('Buddy', 'Golden Retriever');
console.log(myDog.name); // "Buddy"

3. 处理类数组对象

const args = { 0: 'a', 1: 'b', length: 2 };

// 将数组方法应用到类数组对象
Array.prototype.join.call(args, '-'); // "a-b"

4. 绑定回调函数的上下文

class Button {
  constructor() {
    this.clicked = false;
    // 绑定 handleClick 的 this 为当前实例
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.clicked = true;
  }

  render() {
    // 确保回调函数的 this 指向 Button 实例
    document.getElementById('btn').addEventListener('click', this.handleClick);
  }
}

总结

  • call 和 apply:适合需要临时改变 this 指向并立即执行函数的场景。
  • bind:适合需要创建一个永久绑定 this 的新函数(如回调函数、事件处理程序)。