返回

深入理解 JavaScript 中的 call、apply 和 bind

前端

1. call 和 apply:异曲同工,妙用传参

call 和 apply 两个方法的作用基本相同,都是用于改变函数的执行上下文和参数列表。它们的区别在于传参方式不同。

  • call 方法接受两个或多个参数,第一个参数指定了函数体内 this 对象的指向,从第二个参数开始是函数的实际参数。
  • apply 方法也接受两个或多个参数,第一个参数指定了函数体内 this 对象的指向,第二个参数是一个带下标的集合,这个集合包含了函数的实际参数。

举个例子,我们有一个函数叫做 sum,它接受两个参数并返回它们的和。

function sum(num1, num2) {
  return num1 + num2;
}

我们可以使用 call 方法来改变 sum 函数的执行上下文和参数列表,如下所示:

const result = sum.call(null, 1, 2); // result = 3

在这个例子中,我们将 sum 函数的执行上下文设置为 null,并传递了两个参数 12。因此,sum 函数将使用 null 作为 its this 对象,并将 12 作为其参数。

我们也可以使用 apply 方法来改变 sum 函数的执行上下文和参数列表,如下所示:

const result = sum.apply(null, [1, 2]); // result = 3

在这个例子中,我们将 sum 函数的执行上下文设置为 null,并将一个包含 12 的数组作为其参数。因此,sum 函数将使用 null 作为 its this 对象,并将 12 作为其参数。

2. bind:预先绑定,函数柯里化

bind 方法与 call 和 apply 类似,但它不会立即执行函数,而是返回一个新的函数。这个新函数的执行上下文和参数列表已经被预先绑定,因此当它被调用时,将使用预先绑定的执行上下文和参数列表。

举个例子,我们有一个函数叫做 greet,它接受一个参数并返回一个带有该参数的问候语。

function greet(name) {
  return `Hello, ${name}!`;
}

我们可以使用 bind 方法来预先绑定 greet 函数的执行上下文和参数列表,如下所示:

const greetJohn = greet.bind(null, "John"); // greetJohn is a new function

在这个例子中,我们将 greet 函数的执行上下文设置为 null,并预先绑定了参数 "John"。因此,greetJohn 函数将使用 null 作为 its this 对象,并将 "John" 作为其参数。

当我们调用 greetJohn 函数时,它将使用预先绑定的执行上下文和参数列表,如下所示:

const message = greetJohn(); // message = "Hello, John!"

3. 总结与比较

方法 用法 优势 劣势
call func.call(thisArg, arg1, arg2, ...) 直接调用函数 必须手动指定参数
apply func.apply(thisArg, [arg1, arg2, ...]) 直接调用函数 参数必须是数组
bind func.bind(thisArg, arg1, arg2, ...) 返回一个新的函数,该函数的执行上下文和参数列表已经预先绑定 不能立即调用函数

总体来说,call 和 apply 用于直接调用函数,而 bind 用于预先绑定函数的执行上下文和参数列表。在需要改变函数的执行上下文或参数列表时,您可以根据需要选择使用 call、apply 或 bind 方法。

4. 扩展应用:函数柯里化和函数复用

call、apply 和 bind 方法还可以用于函数柯里化和函数复用。

  • 函数柯里化是指将一个函数拆分成一系列更小的函数,每个函数都接受一个参数并返回一个新的函数。这可以使函数更易于复用和组合。
  • 函数复用是指将一个函数用于多个不同的目的。这可以使代码更简洁、更易于维护。

例如,我们可以使用 bind 方法来对 greet 函数进行柯里化,如下所示:

const greetHello = greet.bind(null, "Hello"); // greetHello is a new function
const greetHowdy = greet.bind(null, "Howdy"); // greetHowdy is a new function

现在,我们可以使用 greetHellogreetHowdy 函数来向不同的