在 JavaScript 开发中,call()、apply() 和 bind() 都与函数的 this 有关。它们最核心的作用其实可以简单理解为:
改变函数执行时的 this 指向。
三者的区别主要在于:调用方式、参数传递方式,以及是否立即执行函数。
call():立即执行,参数逐个传递
先看一个简单的例子:
function introduce(city, hobby) {
console.log(
'我叫' + this.name +
',来自' + city +
',喜欢' + hobby
);
}
var user = {
name: '小明'
};
introduce.call(user, '上海', '打球');输出:
我叫小明,来自上海,喜欢打球
这里:
introduce.call(user, '上海', '打球');
可以理解为临时让 introduce 以 user 作为 this 执行。参数形式为:
func.call(thisArg, arg1, arg2, arg3);
call() 会立即执行函数,后面的参数需要一个一个传递。
apply():立即执行,参数以数组传递
apply() 与 call() 的作用基本相同,同样会立即执行函数并指定 this。区别主要在参数传递方式。
function introduce(city, hobby) {
console.log(
'我叫' + this.name +
',来自' + city +
',喜欢' + hobby
);
}
var user = {
name: '小明'
};
introduce.apply(user, ['上海', '打球']);参数形式:
func.apply(thisArg, [arg1, arg2, arg3]);
也就是说:
func.call(obj, arg1, arg2, arg3);
和:
func.apply(obj, [arg1, arg2, arg3]);
执行效果基本相同。
call() 和 apply() 的核心区别
可以直接记成下面这样:
| 方法 | 是否立即执行 | 参数传递方式 |
|---|---|---|
| call() | 是 | 逐个传递 |
| apply() | 是 | 以数组传递 |
例如:
Math.max.call(null, 1, 2, 3, 4);
而 apply():
Math.max.apply(null, [1, 2, 3, 4]);
两者都可以得到:
4
在现代 JavaScript 中,如果只是为了展开数组参数,通常还可以直接使用展开运算符:
Math.max(...[1, 2, 3, 4]);
因此,apply() 过去比较经典的很多使用场景,现在可以通过 ... 更直观地实现。
使用 call() 实现构造函数继承
call() 过去经常用于构造函数之间复用初始化逻辑。例如:
function Human(name, age) {
this.name = name;
this.age = age;
}
function Child(name, age, hobby) {
Human.call(this, name, age);
this.hobby = hobby;
}
var xiaoming = new Child('小明', 10, '打球');
console.log(xiaoming.name);
console.log(xiaoming.hobby);这里:
Human.call(this, name, age);
表示在创建 Child 对象时,让 Human 构造函数使用当前的 this 执行。这样 Child 就可以复用 Human 的初始化逻辑。不过在现代 JavaScript 中,如果使用 class,通常会通过 extends 和 super() 来实现继承,代码会更加清晰。
bind():绑定 this,但不会立即执行
bind() 与 call()、apply() 最大的区别是:
bind() 不会立即调用函数,而是返回一个新的函数。
例如:
function introduce(city, hobby) {
console.log(
'我叫' + this.name +
',来自' + city +
',喜欢' + hobby
);
}
var user = {
name: '小明'
};
var sayHello = introduce.bind(user);
sayHello('上海', '打球');执行:
var sayHello = introduce.bind(user);
时,introduce() 并不会立即运行。
只有后面调用:
sayHello('上海', '打球');函数才真正执行。参数形式可以理解为:
varnewFunc=func.bind(thisArg);
然后:
newFunc(arg1, arg2);
三者对比
| 方法 | 改变 this | 立即执行 | 参数形式 |
|---|---|---|---|
| call() | 是 | 是 | 逐个传递 |
| apply() | 是 | 是 | 数组传递 |
| bind() | 是 | 否 | 返回新函数 |
可以简单记成:
call → 改 this,立即执行,参数逐个传
apply → 改 this,立即执行,参数放数组
bind → 绑定 this,返回新函数
需要注意的 this 问题
call()、apply() 和 bind() 并不是单纯的“改变变量”,而是控制函数执行时的调用上下文。
例如:
function showName() {
console.log(this.name);
}
var user = {
name: 'Hito'
};
showName.call(user);函数内部的:
this.name
会从:
user.name
中获取值。
理解这三个方法,关键不是死记 API,而是理解:
JavaScript 中函数的 this 往往取决于函数如何被调用。
call()、apply() 和 bind() 就是主动控制这种调用上下文的常用方法。
call()、apply() 和 bind() 都可以用来指定函数执行时的 this。
它们最主要的区别只有两点:
- call() 和 apply() 会立即执行函数,bind() 会返回一个新函数。
- call() 使用参数列表,apply() 使用数组形式传递参数。
对于现代 JavaScript 开发来说,call() 和 bind() 仍然非常常见;而 apply() 的部分传统使用场景,现在可以使用展开运算符 ... 代替。
评论0
欢迎分享你的看法,也欢迎补充不同的实践经验。