JavaScript中call和apply方法的区别
技术背景
在JavaScript里,函数属于一等公民,可以拥有自己的方法。call()
和 apply()
是 Function.prototype
上的两个方法,所有函数对象都能通过原型链使用它们。这两个方法的主要作用是在调用函数时指定 this
的值,不过它们在处理函数参数的方式上存在差异。
实现步骤
1. 基本使用
call()
方法:需要将函数的参数逐个列出。apply()
方法:要求将函数的参数放在一个数组中传入。
2. 指定 this
值
在调用函数时,通过这两个方法可以指定函数内部 this
的指向。
3. 根据参数情况选择方法
- 若明确知道参数的数量,或者参数较少,使用
call()
方法更合适。 - 若不清楚参数的数量,或者参数已经存在于一个数组或类数组对象中,使用
apply()
方法更为方便。
核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| function theFunction(name, profession) { console.log("My name is " + name + " and I am a " + profession + "."); }
theFunction("John", "fireman");
theFunction.apply(undefined, ["Susan", "school teacher"]);
theFunction.call(undefined, "Claude", "mathematician");
theFunction.call(undefined, ...["Matthew", "physicist"]);
let obj = { val1: 5, val2: 10 };
const summation = function (val3, val4) { return this.val1 + this.val2 + val3 + val4; };
console.log(summation.apply(obj, [2, 3]));
console.log(summation.call(obj, 2, 3));
|
最佳实践
1. 借用方法
一个对象可以借用另一个对象的方法,通过 call()
或 apply()
方法指定 this
的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| var friend = { car: false, lendCar: function (canLend) { this.car = canLend; } };
var me = { car: false, gotCar: function () { return this.car === true; } };
console.log(me.gotCar());
friend.lendCar.call(me, true); console.log(me.gotCar());
friend.lendCar.apply(me, [false]); console.log(me.gotCar());
|
2. 求数组的最大值和最小值
可以使用 apply()
方法将数组作为参数传递给 Math.max()
或 Math.min()
函数。
1 2 3
| var numbers = [5, 6, 2, 3, 7]; var max = Math.max.apply(null, numbers); var min = Math.min.apply(null, numbers);
|
常见问题
1. this
值为 null
或 undefined
的情况
当 null
或 undefined
作为 call()
或 apply()
的第一个参数时,全局对象会被用作 this
的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var obj = { value: 10, addValues: function () { for (var i = 0; i < arguments.length; i++) { this.value += arguments[i]; } return this.value; } };
var f = obj.addValues;
obj.addValues.call(undefined, 10, 20, 30); obj.addValues.apply(undefined, [10, 20, 30]);
|
2. 性能差异
一般来说,如果参数已经是数组,使用 apply()
更合适;如果参数不是数组,使用 call()
可能会更快,因为 apply()
需要对数组进行评估。不过这种性能差异在不同浏览器中可能有所不同。