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