call和apply的作用
重要定義: call和apply是為了動態的改變this而出現的(記住這句話),如果一個A對象沒有某個方法fn,而另一B對象有,則可以調用A對象的call或apply,然后傳入B對象,這樣B對象就沒必要定義新的fn方法了。
語法:
-
fun.call(thisArg[, arg1[, arg2[, ...]]])
- thisArg: fun函數運行時指定的this值。需要注意的是,this值并不一定是該函數執行時真正的this值;當在非嚴格模式下,如果該值為null或undefined,那么this指向的是全局對象(也就是瀏覽器中的window對象);如果該值為基本類型(數值、字符串、布爾值),那么this將指向基本類型值的自動包裝對象
- arg1, arg2 .....: 參數列表
-
fun.apply(thisArg, [argArray])
- thisArg:與call方法的類似
-
[argArray]:一個數組或類數組對象。其中的數組元素將作為單獨的參數傳給fun函數(重要:參數元素將作為單獨的參數傳給fun函數);如果該值為null或undefined,則表示不需要傳入任何參數。
Tips: 關于apply方法有一個很典型的用法就是使用它來求一個數組對象中的最大最小值(Math.max.apply(null|undefined, array) 和 Math.min.apply(null|undefined, array)),因為這兩個方法不接受對象(其原型:Math.max([value1[, value2[, ...]]])),調用apply方法后,會將傳入的數組對象中的數組元素作為單獨的參數傳入max和min方法中,這樣就符合max和min的使用規則了
兩者的不同點:使用call時,傳入的是參數列表;而使用apply,傳入的是數組或類數組對象;
示例1:使用call方法調用父構造函數
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
//這里調用Product, this表示的是Food,這樣Food里也擁有了name和price屬性
Product.call(this, name, price);
this.category = 'food';
}
function Toy(name, price) {
// 這里調用Product,this表示的是Toy,這樣Toy里也擁有了name和price屬性
Product.call(this, name, price);
this.category = 'toy';
}
var product = new Product('car', '200k');
var fruit = new Food('apple', '5');
var toy = new Toy('robot', '5k');
上面代碼中,可以將Product看成一個父構造函數,Fruit和Food是Product下的兩個子構造函數
示例2:使用call方法調用匿名函數
在這個例子中,創建了一個匿名函數,然后調用匿名函數的call方法,將數組元素作為指定的this值執行那個匿名函數(相當于匿名函數中this就指向了傳入的數組元素),這個匿名函數的作用是給每個數組元素添加一個print方法。
var animal = [
{specis: 'lion', name: 'King'},
{specis: 'Whale', name: 'Fail'}
];
for (var i = 0; i < animal.length; i++) {
(function(i){
this.print = function(){
console.log('#' + i + ' ' + this.specis + ': ' + this.name);
};
this.print();
}).call(animal[i], i);
}
示例3:使用call方法調用函數并且執行上下文
當調用greet的call方法時,會將greet中的this綁定到i
function greet(){
var reply = [this.person, 'is an Awesome', this.role].join(' ');
console.log(reply);
}
var i = {
person: 'Douglas Crockford',
role: 'Javascript developer'
};
greet.call(i);
示例4:使用apply和內置函數
var arr = [100, 10, 2, 20, 1];
console.log(Math.max.apply(null, arr));
注意事項
如下代碼所示:
var arr = [1, 10, 20, 0, -1];
Math.math.apply(null, arr));
function convertArray() {
return Array.prototype.slice.apply(arguments);
}
為什么Math.math.apply()
中的第一個參數為null,而Array.prototype.slice.apply
中的第一個參數為需要處理的數據?
猜測:
因為Math.math()
方法的原型是:Math.max([value1[,value2[,...]]])
;也就是說它的參數是直接傳入的,不需要去指定this
,因此調用apply時,this
指向null,實參放到第二個參數中;
而slice的原型是objArr.slice([begin[,end]]);
,也就是說slice()
是在數組對象上調用的,因此,必須要為其指定this
指向,也就是將arguments
放到第一個參數中;
總結:凡是涉及到調用對象的方法,都需要為其指定this