返回

「编程向自由」改变 This 指向的三种方式:CALL、APPLY、BIND

前端

理解 JavaScript 中的 this:改变函数调用的风向

一、this 指向的迷宫

在 JavaScript 的世界中,this 关键词是一个既强大又容易令人困惑的家伙。它会根据函数调用的方式,动态地指向不同的对象。这可能会导致意想不到的行为,让人一头雾水。

想象一下这样的场景:你正使用一个对象的某个方法,但 this 却指向了全局对象 window。或者,你在一个嵌套函数中使用 this,结果指向了错误的对象。这些情况不仅令人沮丧,还会影响代码的正确运行。

二、掌控 this 指向的利器:call、apply、bind

为了应对这些挑战,JavaScript 提供了三个强大的方法:callapplybind。它们允许你指定函数调用的 this 指向,从而掌控代码的执行。

1. call

call 方法让你指定一个函数的 this 指向。它就像一个万能遥控器,可以将 this 指向你想指向的任何对象。其语法如下:

functionName.call(thisArg, arg1, arg2, ...)
  • functionName:要调用的函数。
  • thisArg:指定函数调用的 this 指向。
  • arg1, arg2, ...:要传递给函数的参数。

举个例子,假设我们有一个对象 person,里面有一个方法 greet,它打印出 this.name。使用 call 方法,我们可以让 this 指向另一个对象 anotherPerson

const person = {
  name: 'John',
  greet: function() {
    console.log(`Hello, my name is ${this.name}.`);
  }
};

const anotherPerson = {
  name: 'Mary'
};

person.greet.call(anotherPerson); // 输出:"Hello, my name is Mary."

2. apply

apply 方法与 call 方法类似,但它允许你传递一个参数数组给函数。其语法如下:

functionName.apply(thisArg, [arg1, arg2, ...])
  • functionName:要调用的函数。
  • thisArg:指定函数调用的 this 指向。
  • [arg1, arg2, ...]: 要传递给函数的参数数组。

同样,我们可以使用 apply 方法将 this 指向 anotherPerson

person.greet.apply(anotherPerson, ['Alice']); // 输出:"Hello, my name is Alice."

3. bind

bind 方法与 callapply 方法有所不同。它不会立即调用函数,而是返回一个新的函数,这个新函数的 this 指向被固定为指定的 thisArg。其语法如下:

functionName.bind(thisArg, arg1, arg2, ...)
  • functionName:要绑定的函数。
  • thisArg:指定函数绑定的 this 指向。
  • arg1, arg2, ...:要传递给新函数的参数。

让我们再次使用 person 对象进行演示:

const boundGreet = person.greet.bind(person);

boundGreet(); // 输出:"Hello, my name is John."

即使我们直接调用 boundGreetthis 指向仍然是 person 对象。

三、DIY:实现自己的 my

如果你对 callapplybind 的实现原理感兴趣,你可以尝试自己实现一个 my 函数。以下是它的简化版本:

function my(func, thisArg, ...args) {
  const boundFunc = function() {
    func.apply(thisArg, args);
  };

  boundFunc.prototype = func.prototype;

  return boundFunc;
}

这个 my 函数可以像 callapply 一样使用:

const boundGreet = my(person.greet, person);

boundGreet(); // 输出:"Hello, my name is John."

四、应用场景

了解了 callapplybind,你可以轻松解决各种 JavaScript 编程问题,例如:

  • 当你希望改变函数调用的 this 指向时。
  • 当你想要创建固定 this 指向的新函数时。
  • 当你想要传递参数数组给函数时。

五、常见问题解答

  1. Q:callapplybind 有什么区别?
    A:callapply 立即调用函数,而 bind 返回一个新函数。apply 允许你传递参数数组,而 call 则必须一个个传递参数。

  2. Q:为什么使用 bind 而不是 callapply
    A:bind 很适合创建固定 this 指向的新函数,特别是在你需要多次调用该函数时。

  3. Q:我可以将 callapplybind 用于箭头函数吗?
    A:不可以,箭头函数的 this 指向是固定的,无法通过 callapplybind 改变。

  4. Q:如何处理异步函数的 this 指向?
    A:可以使用箭头函数或显式绑定 (bind) 来确保异步函数中的 this 指向正确。

  5. Q:my 函数与原生的 callapplybind 有什么区别?
    A:my 函数只是一个简化版本,不提供所有原生方法的完整功能。