「编程向自由」改变 This 指向的三种方式:CALL、APPLY、BIND
2022-11-04 07:44:44
理解 JavaScript 中的 this:改变函数调用的风向
一、this 指向的迷宫
在 JavaScript 的世界中,this
关键词是一个既强大又容易令人困惑的家伙。它会根据函数调用的方式,动态地指向不同的对象。这可能会导致意想不到的行为,让人一头雾水。
想象一下这样的场景:你正使用一个对象的某个方法,但 this
却指向了全局对象 window
。或者,你在一个嵌套函数中使用 this
,结果指向了错误的对象。这些情况不仅令人沮丧,还会影响代码的正确运行。
二、掌控 this 指向的利器:call、apply、bind
为了应对这些挑战,JavaScript 提供了三个强大的方法:call
、apply
和 bind
。它们允许你指定函数调用的 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
方法与 call
和 apply
方法有所不同。它不会立即调用函数,而是返回一个新的函数,这个新函数的 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."
即使我们直接调用 boundGreet
,this
指向仍然是 person
对象。
三、DIY:实现自己的 my
如果你对 call
、apply
和 bind
的实现原理感兴趣,你可以尝试自己实现一个 my
函数。以下是它的简化版本:
function my(func, thisArg, ...args) {
const boundFunc = function() {
func.apply(thisArg, args);
};
boundFunc.prototype = func.prototype;
return boundFunc;
}
这个 my
函数可以像 call
和 apply
一样使用:
const boundGreet = my(person.greet, person);
boundGreet(); // 输出:"Hello, my name is John."
四、应用场景
了解了 call
、apply
和 bind
,你可以轻松解决各种 JavaScript 编程问题,例如:
- 当你希望改变函数调用的
this
指向时。 - 当你想要创建固定
this
指向的新函数时。 - 当你想要传递参数数组给函数时。
五、常见问题解答
-
Q:
call
、apply
和bind
有什么区别?
A:call
和apply
立即调用函数,而bind
返回一个新函数。apply
允许你传递参数数组,而call
则必须一个个传递参数。 -
Q:为什么使用
bind
而不是call
或apply
?
A:bind
很适合创建固定this
指向的新函数,特别是在你需要多次调用该函数时。 -
Q:我可以将
call
、apply
和bind
用于箭头函数吗?
A:不可以,箭头函数的this
指向是固定的,无法通过call
、apply
或bind
改变。 -
Q:如何处理异步函数的
this
指向?
A:可以使用箭头函数或显式绑定 (bind
) 来确保异步函数中的this
指向正确。 -
Q:
my
函数与原生的call
、apply
和bind
有什么区别?
A:my
函数只是一个简化版本,不提供所有原生方法的完整功能。