数字营销 · Web开发 · 基础设施

JavaScript 中 call、apply 和 bind 的区别与应用

call()、apply() 和 bind() 都可以控制 JavaScript 函数执行时的 this。本文通过实际示例介绍三者的区别,包括参数传递方式、是否立即执行,以及在函数复用和继承中的应用。

在 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。

它们最主要的区别只有两点:

  1. call() 和 apply() 会立即执行函数,bind() 会返回一个新函数。
  2. call() 使用参数列表,apply() 使用数组形式传递参数。

对于现代 JavaScript 开发来说,call() 和 bind() 仍然非常常见;而 apply() 的部分传统使用场景,现在可以使用展开运算符 ... 代替。

评论0

欢迎分享你的看法,也欢迎补充不同的实践经验。