JS中每个函数都包含两个非继承而来的方法: apply( ) 和 call( ) 。
这两个方法的用途都是:在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。
apply( ) 接受两个参数:一个是在其中运行函数的作用域,另一个是参数数组(既可以是 Array 的实例,也可以是 arguments 对象)。例:
var num1 = 222, num2 = 333, num3 = 444;
function sum(num1, num2, num3){ //求和函数
return num1 + num2 + num3;
}
function callSum1(num1, num2){
let num3 = 3;
let argu = [num1, num2, num3];
return sum.apply(this, argu); //sum()函数中可以使用let变量
}
function callSum2(num1, num2, num3){
return sum.apply(this, arguments); //arguments传参
}
function callSum3(num1, num2, num3){
return sum.apply(this, [num1, num2, num3]); //传入数组
}
console.log(callSum1(1, 2)); //6
console.log(callSum2(10, 20, 30)); //60
console.log(callSum3(0, 0, 1)); //1
> callSum1( ) 在执行 sum( ) 函数时传入了 this 作为 this 值(因为是在全局中调用的,所以传入的就是 window 对象)。
call( ) 接受的第一个参数与 apply( ) 一样,但后面传递给函数的参数必须逐个列举出来。例:
function sum(num1, num2){
return num1 + num2;
}
function callSum(num1, num2){
return sum.call(this, num1, num2); //必须明确地传入每一个参数
}
console.log(callSum(1, 2)); //3
这两个方法主要的用处并不是用来传参,而是能够扩充函数赖以运行的作用域。
例:
window.color = "red";
var o = { color: "blue" };
function sayColor(){
console.log(this.color);
}
sayColor(); //red
sayColor.call(this); //red
sayColor.call(window); //red
sayColor.call(o); //blue
> sayColor( ) 在全局环境下定义的,是全局函数,所以在全局作用域中调用它时,输出 "red"(因为对 this.color 的求值会转换成 window.color 的求值)。而 sayColor.call(this) 和 sayColor.call(window) 则是两种显式地在全局作用域中调用函数的方式,所以输出 "red" 。但当函数的执行环境指向 o 时,this.color 的值就为 "blue" 。
使用 call() 和 apply() 来扩充作用域的最大好处,就是对象不需要与方法有任何耦合关系。
看一个例子:
window.num1 = 1;
window.num2 = 2;
var o = { num1: 11, num2: 22 };
var oo = { num1: 111, num2: 222 };
function saySum(){
console.log(this.num1 + this.num2);
}
saySum(); //3
saySum(this); //3
saySum(window); //3
saySum.apply(o); //33
saySum.call(o); //33
saySum.apply(oo); //333
> 函数 saySum( ) 与对象 o 和 oo 之间没有任何耦合关系,通过 call( ) 或 apply( ) 建立联系。
另一个例子:
window.sum1 = function(num1, num2){
return num1 + num2;
};
var o = { sum1: function(num1, num2){
return num1 + num2 + 222;
} };
var oo = { sum1: function(num1, num2){
return num1 + num2 + 333;
} };
function saySum(){
console.log(this.sum1(1, 2));
}
saySum.apply(); //3
saySum.apply(o); //225
saySum.apply(oo); //336