剛接觸 apply() 的時候總是模棱兩可,似懂非懂,公司的前輩說這個方法就是為了改變函數(shù)的 this 。具體到底是如何改變,在什么場景下改變呢?來好好梳理一下吧~
(一)語法:
Function.prototype.apply()
fun.apply(thisArg, [argsArray])
thisArg: 在fun函數(shù)運行時指定的this值,即這個參數(shù)將替換 fun 里面的 this 對象。
[argsArray]: 這個參數(shù)是一個數(shù)組,將作為參數(shù)傳給 fun。很神奇的是,它雖然是數(shù)組格式,但卻會先默默轉(zhuǎn)換成列表格式,再傳參給 fun 。
Function.prototype.call()
fun.call(thisArg[, arg1[, arg2[, ...]]])
thisArg: 在fun函數(shù)運行時指定的this值,這個參數(shù)將替換 fun 里面的 this 對象。
arg1, arg2, ...:傳給 fun 函數(shù)的參數(shù)列表。
(二)兩者的區(qū)別:
call() 方法接受的是若干個參數(shù)的列表,而 apply() 方法接受的是一個包含多個參數(shù)的數(shù)組。
(三)看幾個常用的使用場景:
示例一:
在調(diào)用方法的時候使用,改變 this 對象。
function Cat(){
}
Cat.prototype={
food:"fish",
say: function(){
console.log("I love "+this.food);
}
}
var blackCat = new Cat;
blackCat.say(); // say方法里面的this是Cat()
function Dog(){
}
Dog.prototype={
food:"bone"
}
var blackDog = new Dog;
blackCat.say.apply(blackDog); // I love bone ,相當(dāng)于在這執(zhí)行了blackCat.say(),但是say方法里面的this被改變,變成了dog()
示例二:
在函數(shù)內(nèi)部使用, 調(diào)用其它對象的方法給自己使用,經(jīng)常會傳到參數(shù)。
function Person(name, age){
this.name=name;
this.age=age;
}
function Student(name, age, grade){
Person.apply(this,arguments); // 相當(dāng)于在這執(zhí)行了Person(),只是Person里面的this變成了Student,arguments將作為參數(shù)傳給Person
// call的寫法
// Person.call(this, name, age);
this.grade=grade;
}
var student=new Student("zhangsan",21,"一年級");
console.log("name:"+student.name+"\n"+"age:"+student.age+"\n"+"grade:"+student.grade);
// name:zhangsan
// age:21
// grade:一年級
示例三:
在一個異步的函數(shù)中用于引入一個回調(diào)函數(shù)。
function aFun(cate, callback) {
var self = this;
$.ajax(url)
.done(function(){
if (cate == 'success') {
callback.call(self, arg); //在這里執(zhí)行 callback,arg 是傳給 callback 的參數(shù)
}
})
.fail(function(){
if (cate == 'failure') {
callback.call(self, arg);
}
})
}
aFun('success', function(arg) {
console.log('成功啦~')
})
aFun('failure', function(arg) {
console.log('失敗了。。。')
})
(四)apply() 的妙用
利用了“apply的第二個參數(shù)值,是一個數(shù)組,可以自動轉(zhuǎn)換為一個參數(shù)列表”這一特性。
求一個數(shù)組中的最大值/最小值
var num = [10, 0, 3, 15];
console.log( Math.max(10, 0, 3, 15)); // Math.max方法的參數(shù)僅支持列表形式
console.log( Math.max.apply(null, num)); //第一個參數(shù)用null,因為沒有對象去調(diào)用這個方法,只需要把num作為參數(shù)傳入Math.max()方法,并得到返回的結(jié)果
合并兩個數(shù)組
var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
Array.prototype.push.apply(arr1, arr2); // Array.prototype.push() 方法的參數(shù)僅支持列表形式
console.log(arr1); // [1, 2, 3, 4, 5, 6]
console.log(arr2); // [4, 5, 6]
(五)什么時候用 apply(),什么時候用call()
綜上所述我們可以總結(jié)下這兩個方法的使用場景:
- 如果只有一個參數(shù)時,用哪個方法都是一樣的。
- 如果被調(diào)用的函數(shù)參數(shù)只支持列表形式,而現(xiàn)有的參數(shù)是數(shù)組形式,可以用apply() 巧妙的轉(zhuǎn)換。
- 使用 apply() 時,要注意參數(shù)數(shù)組里的順序是否對得上,如果現(xiàn)有參數(shù)的順序不是要求的,這時候用 call() 指定參數(shù)傳入的順序。例如:
function Person(name, age){
this.name=name;
this.age=age;
}
function Student(age, name, grade){
Person.apply(this,arguments); // 如果這時候用這種寫法就會出錯,
Person.call(this, name, age); // 這時候用call,可以指定參數(shù)傳入的順序
this.grade=grade;
}