call 和 apply 方法的区别
- 参数传递方式:
call
方法的第一个参数是 this
的指向,从第二个参数开始往后,都是传递给函数的参数。例如:func.call(thisArg, arg1, arg2, ...)
。
apply
方法的第一个参数同样是 this
的指向,第二个参数是一个包含所有要传递给函数参数的数组(或类数组对象)。例如:func.apply(thisArg, [arg1, arg2, ...])
。
- 性能差异:
- 一般情况下两者性能差异不大。但在传递大量参数时,由于
call
需要逐个列出参数,代码可能会显得冗长,而 apply
只需要传递一个数组,在这种场景下代码可能更简洁,且从理论上来说,在引擎解析参数时,apply
传递单个数组比 call
传递多个离散参数可能在某些情况下性能略好(但实际中这种差异极难察觉)。
实际开发中的适用场景
- call 适用场景:
- 继承:在实现继承时经常使用
call
来调用父类构造函数,确保子类能继承父类的属性。例如:
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name +'makes a sound.');
};
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
let myDog = new Dog('Buddy', 'Golden Retriever');
myDog.speak();
- 函数复用:当有一个通用函数,需要在不同
this
环境下调用时,且参数个数固定且较少。比如有一个格式化日期的函数,在不同对象下调用,且传递少量参数:
function formatDate(date, format) {
// 日期格式化逻辑
return formattedDate;
}
let obj1 = { date: new Date() };
let obj2 = { date: new Date('2023 - 10 - 01') };
let formatStr = 'yyyy - MM - dd';
let result1 = formatDate.call(obj1, obj1.date, formatStr);
let result2 = formatDate.call(obj2, obj2.date, formatStr);
- apply 适用场景:
- Math.max/min 结合数组使用:当需要获取数组中的最大或最小值时,
apply
可以很方便地将数组作为参数传递。例如:
let numbers = [1, 5, 3, 9, 7];
let max = Math.max.apply(null, numbers);
let min = Math.min.apply(null, numbers);
console.log(max); // 9
console.log(min); // 1
- 函数参数不确定个数时:如果函数接收的参数个数不确定,通过数组收集参数后使用
apply
调用函数会很方便。例如,模拟一个可以接收任意数量参数并计算总和的函数:
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
let numArray = [1, 2, 3, 4];
let result = sum.apply(null, numArray);
console.log(result); // 10