2024-12-13    2024-12-13    1385 字  3 分钟

callapplybind 是 JavaScript 中用于控制函数执行上下文(即 this 的值)的三个重要方法。它们的主要作用是允许你显式地指定函数内部的 this 指向。

基础

call

call 方法用于立即调用函数,并指定函数内部的 this 值。它还可以传递参数给函数。

语法:

1
function.call(thisArg, arg1, arg2, ...)
  • thisArg:指定函数执行时的 this 值。
  • arg1, arg2, ...:传递给函数的参数。

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const person = {
  name: "Alice",
  greet: function(greeting) {
    console.log(`${greeting}, ${this.name}!`);
  }
};

const anotherPerson = {
  name: "Bob"
};

person.greet.call(anotherPerson, "Hello"); // 输出: Hello, Bob!

在这个例子中,callgreet 函数的 this 指向了 anotherPerson,因此 this.name 变成了 "Bob"

apply

apply 方法与 call 类似,也是用于立即调用函数,并指定函数内部的 this 值。不同的是,apply 传递参数时使用数组形式。

语法:

1
function.apply(thisArg, [argsArray])
  • thisArg:指定函数执行时的 this 值。
  • argsArray:传递给函数的参数数组。

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const person = {
  name: "Alice",
  greet: function(greeting, punctuation) {
    console.log(`${greeting}, ${this.name}${punctuation}`);
  }
};

const anotherPerson = {
  name: "Bob"
};

person.greet.apply(anotherPerson, ["Hello", "!"]); // 输出: Hello, Bob!

在这个例子中,applygreet 函数的 this 指向了 anotherPerson,并通过数组传递了参数。

bind

bind 方法不会立即调用函数,而是返回一个新函数,并将 this 绑定到指定的对象。你可以稍后调用这个新函数。

语法:

1
const newFunction = function.bind(thisArg, arg1, arg2, ...)
  • thisArg:指定函数执行时的 this 值。
  • arg1, arg2, ...:传递给函数的参数(可选)。

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const person = {
  name: "Alice",
  greet: function(greeting) {
    console.log(`${greeting}, ${this.name}!`);
  }
};

const anotherPerson = {
  name: "Bob"
};

const greetBob = person.greet.bind(anotherPerson, "Hello");
greetBob(); // 输出: Hello, Bob!

在这个例子中,bind 返回了一个新函数 greetBob,它的 this 被绑定到 anotherPerson,并且预设了参数 "Hello"

总结对比

方法 是否立即执行 参数传递方式 返回值
call 逐个传递(逗号分隔)
apply 数组形式
bind 逐个传递(可选) 返回一个新函数

使用场景

  1. callapply

    • 当你需要立即调用一个函数,并指定 this 时。
    • 例如:借用方法(从一个对象借用方法到另一个对象)。
  2. bind

    • 当你需要创建一个新函数,并绑定 this 时。
    • 例如:事件处理函数、回调函数。

示例:借用方法

1
2
3
const array = [1, 2, 3];
const max = Math.max.apply(null, array); // 使用 apply 借用 Math.max
console.log(max);                        // 输出: 3

在这个例子中,Math.max 方法通常接受多个参数,但通过 apply,我们可以将数组作为参数传递。

注意事项

  1. thisArgnullundefined

    • 如果 thisArgnullundefinedthis 将指向全局对象(在浏览器中是 window)。
  2. bind 的永久绑定

    • 一旦使用 bind 绑定 this,后续无法通过 callapply 改变 this 的值。

通过掌握 callapplybind,你可以更灵活地控制函数的行为,尤其是在处理对象方法和回调函数时非常有用。

附录

如何理解“bind 的永久绑定”?

❓问:如何理解“一旦使用 bind 绑定 this,后续无法通过 callapply 改变 this 的值” ?

❗答: bind 的实现原理是创建一个新的函数,并将 this 硬编码到这个新函数中。因此,无论你如何调用这个新函数,它的 this 值都不会改变。

下面让我们看一下其 「底层原理 」

当你使用 bind 时,JavaScript 引擎会生成一个新的函数,类似于以下伪代码:

1
2
3
function boundFunction() {
  return originalFunction.call(boundThis, ...arguments);
}

其中:

  • boundThis 是 bind 绑定的对象。
  • originalFunction 是原始函数。

在这个新函数中,this 已经被硬编码为 boundThis,因此无法通过 call 或 apply 改变。

❓问:那可不可以再次使用 bind 改变 this 的指向呢?

❗答:不可以! bind 的绑定是不可变的:即使你多次使用 bind,也不会覆盖之前的绑定。

这种特性使得 bind 非常适合用于创建回调函数或事件处理函数,因为你可以确保 this 的值在任何情况下都不会改变。