JavaScript 中 call、apply 和 bind 的用法与区别
一、对比
方法 | 调用方式 | 参数传递方式 | 是否立即执行 | 优点 | 缺点 | 典型使用场景 |
---|---|---|---|---|---|---|
call | 立即调用 | 依次传递多个独立参数 | 是 | 灵活改变 this 指向并立即执行,方便传递多个已知参数 | 参数较多时代码冗长 | 对象方法调用、函数参数已知的情况 |
apply | 立即调用 | 传递一个数组(类数组) 作为参数 |
是 | 适合将数组或类数组作为参数传递,代码简洁 | 参数必须是数组或类数组 | 数组参数处理、类数组操作 |
bind | 返回新函数 | 可预先设定 this 和部分参数 | 否 | 可创建新函数,预设 this 和参数,提高代码复用性和灵活性 | 创建新函数可能增加内存占用 | 需要预设上下文和参数的场景,如事件处理 |
二、call 方法
用法
call 方法会调用函数,并将函数内部的 this 指向指定的对象,同时可以传递参数给函数。
语法:
javascript
function.call(thisArg, arg1, arg2, ...)
举例
javascript
const person = {
name: "John",
greet: function(age, hobby) {
console.log(`Hello, my name is ${this.name}. I am ${age} years old and I like ${hobby}.`);
}
};
person.greet(30, "reading"); // 直接调用,this 指向 person
// Hello, my name is John. I am 30 years old and I like reading.
const anotherPerson = {
name: "Jane"
};
person.greet.call(anotherPerson, 25, "cooking"); // 使用 call,this 指向 anotherPerson
// Hello, my name is Jane. I am 25 years old and I like cooking.
优点
- 可以灵活地改变函数内部的 this 指向,调用函数并立即执行。
- 能够方便地为函数传递多个参数,参数依次传递。(写的时候很爽,复用的时候太恶心)
缺点
- 如果参数数量较多,在调用 call 时需要逐个列出参数,代码可能会显得冗长。(所以尽量用apply,因为apply和call的不同就是传参方式,apply中只传一个数据即可)
三、apply 方法 (重点,常用)
用法
apply 方法也用于调用函数,指定函数内部的 this 指向,但它接受一个数组(或类数组对象)作为函数的参数。
语法:
javascript
function.apply(thisArg, [argsArray])
举例
javascript
const numbers = [1, 2, 3, 4, 5];
const max = Math.max.apply(null, numbers); // 使用 apply,将数组元素作为参数传递给 Math.max
console.log(max); // 5
const person = {
name: "John",
greet: function(...args) {
console.log(`Hello, my name is ${this.name}. I like ${args.join(", ")}.`);
}
};
const hobbies = ["reading", "cooking", "hiking"];
person.greet.apply(person, hobbies); // 使用 apply 传递数组参数
// Hello, my name is John. I like reading, cooking, hiking.
优点
- 适合将数组或类数组对象作为参数传递给函数,避免逐个列出参数,使代码更简洁。
缺点
- 参数必须是一个数组或类数组对象,不能像 call 那样直接传递多个独立参数。(复用的时候很爽)
使用场景
- 防抖、节流中,可以用apply来更改闭包中return出来的function的this指向,从而可以在方法函数中用this指向来添加业务逻辑
四、bind 方法
用法
bind 方法会创建一个新函数,并将新函数内部的 this 指向指定的对象。调用 bind 不会立即执行函数,而是返回一个新函数,这个新函数可以在后续被调用。
语法:
javascript
const newFunction = function.bind(thisArg, arg1, arg2, ...)
举例
javascript
const person = {
name: "John",
greet: function(time, ...hobbies) {
console.log(`Good ${time}, my name is ${this.name}. I like ${hobbies.join(", ")}.`);
}
};
const greetMorning = person.greet.bind(person, "morning");
greetMorning("reading", "cooking"); // Good morning, my name is John. I like reading, cooking.
const anotherPerson = {
name: "Jane"
};
const anotherGreet = person.greet.bind(anotherPerson, "afternoon");
anotherGreet("hiking", "painting"); // Good afternoon, my name is Jane. I like hiking, painting.
优点
- 可以预先设定函数的 this 指向和部分参数,创建一个新函数,这个新函数可以在之后被多次调用,提高代码的复用性和灵活性。
- 在事件处理函数或定时器等场景中非常有用,可以提前绑定好上下文,避免在回调中手动设置 this。
缺点
- 创建了一个新的函数,如果频繁使用可能会增加内存占用,相比之下 call 和 apply 是直接调用函数。
使用场景
- 当需要预先设定函数的上下文和部分参数,但又不希望立即执行函数,而是稍后多次调用时。例如,在设置事件监听器时,提前绑定好对象的方法作为事件处理函数,这样在事件触发时,函数内部的 this 就已经正确指向了设定的对象。