call(),apply()方法的作用都是用來(lái)改變函數(shù)運(yùn)行時(shí)的上下文(Context),那么什么是上下文呢?
關(guān)于上下文
上下文就是函數(shù)中this的值,它的值等于函數(shù)運(yùn)行時(shí),調(diào)用這個(gè)函數(shù)的對(duì)象,也就是說(shuō),上下文是可以動(dòng)態(tài)改變的,隨著函數(shù)執(zhí)行環(huán)境的不同,它的值也會(huì)發(fā)生變化。比如:
- 在全局作用于中調(diào)用函數(shù),函數(shù)的上下文為
Global對(duì)象(在瀏覽器中為window對(duì)象),eg:
var name = 'JavaScript';
function sayName (){
console.log(this.name);
}
// 在全局作用域中調(diào)用sayName,此時(shí)相當(dāng)與window.sayName();
// 所以此時(shí)的 this = window,即函數(shù)運(yùn)行時(shí)的上下文為: window對(duì)象
sayName();
- 在特定對(duì)象中調(diào)用函數(shù),
this指向這個(gè)對(duì)象,eg:
function Cat(name,sound) {
this.name = name;
this.sound = sound;
}
Cat.prototype.speak =function () {
console.log(`${this.name} speak ${this.sound}`);
}
var mipang = new Cat('mipang','喵喵喵~~');
// 在對(duì)象mipang中調(diào)用函數(shù)speak,此時(shí)函數(shù)speak內(nèi)部的指針指向mipang
// mipang有兩個(gè)屬性,name:'mipang',sound:'喵喵喵~~';
// 所以輸出是: mipang speak 喵喵喵??!
mipang.speak();
call()、apply()語(yǔ)法
通過(guò)上面的例子,我們對(duì)上下文有了一個(gè)基本概念,此時(shí)我們?cè)賮?lái)討論call(),apply()
如一開(kāi)始所說(shuō),call()和apply()都是用來(lái)改變函數(shù)執(zhí)行時(shí)的上下文的,兩者的區(qū)別是傳參方式的不同:
// call()具有多個(gè)參數(shù),apply方法只有兩個(gè)參數(shù);
// 兩者的第一個(gè)參數(shù)都是一個(gè)對(duì)象obj,用來(lái)改變函數(shù)function的上下文;
// 即 函數(shù)function中的this指向obj對(duì)象;
function.call(obj,arg1,arg2,arg3,...); // 第一個(gè)參數(shù)后面的參數(shù)是一個(gè)參數(shù)列表
function.apply(obj,[arg1,arg2,arg3,...]) // 第二個(gè)參數(shù)是一個(gè)數(shù)組,數(shù)組的元素為函數(shù)的參數(shù),即將call()方法的參數(shù)列表寫(xiě)成數(shù)組形式
我們舉個(gè)例子來(lái)說(shuō)一下call和apply的具體用法:
// 創(chuàng)建對(duì)象bajie,bajie有個(gè)introduce方法可以用來(lái)介紹自己的光輝事跡
var bajie = {
name: '豬八戒',
introduce: function (job,ability) {
console.log(job + this.name + ability);
}
}
bajie.introduce('天蓬大元帥','調(diào)戲嫦娥仙子'); //天蓬大元帥豬八戒調(diào)戲嫦娥仙子
// 創(chuàng)建對(duì)象wukong,wukong并沒(méi)有一個(gè)介紹自己光輝事跡的introduce方法
var wukong = {
name: '孫悟空'
}
假設(shè)我們想讓wukong也有辦法來(lái)介紹自己的光輝事跡,可以給對(duì)象wukong添加一個(gè)相同的introduce方法
假設(shè)我們也想給牛魔王、白骨精、金角大王等等相同的能力,難道要分別給每一個(gè)創(chuàng)建這個(gè)方法嗎?當(dāng)然不是,這個(gè)時(shí)候call(),apply()就派上用場(chǎng)了:
bajie.introduce.call(wukong,'齊天大圣','調(diào)戲嫂嫂鐵扇公主');
bajie.introduce.apply(wukong,['齊天大圣','調(diào)戲嫂嫂鐵扇公主']);
// 齊天大圣孫悟空調(diào)戲嫂嫂鐵扇公主
我們來(lái)看一個(gè)實(shí)際應(yīng)用場(chǎng)景:
function Animal(name,food,sound){
this.name = name;
this.food = food;
this.sound = sound;
}
Animal.prototype.speak = function() {
console.log(this.name+'愛(ài)吃'+this.food+' '+this.sound);
}
function Cat(name,food,sound) {
// Animal.call(this,name,food,sound);
Animal.apply(this,arguments);
}
Cat.prototype = new Animal();
var cat = new Cat('咪胖','魚(yú)','喵喵喵~');
cat.speak(); // 咪胖愛(ài)吃魚(yú) 喵喵喵~
apply()方法特性:
apply方法會(huì)將默認(rèn)將參數(shù)數(shù)組轉(zhuǎn)換為參數(shù)列表,利用這一特性,有下面幾個(gè)應(yīng)用:
- 數(shù)組合并:
var arr1 = [1,2,3];
var arr2 = [4,5,6];
// 因?yàn)閜ush()方法只接受參數(shù)列表,利用apply的特性將數(shù)組參數(shù)轉(zhuǎn)為參數(shù)列表
arr1.push.apply(arr1,arr2);
// 或者Array.prototype.push.apply(arr1,arr2);
console.log(arr1); // [1,2,3,4,5,6]
// 該方法接受參數(shù)列表,并將參數(shù)列表轉(zhuǎn)為數(shù)組返回
function transtoArray(){
var values = new Array();
values.push.apply(values,arguments);
return values;
}
var arr = transtoArray('張三','李四','王五','趙六');
console.log(arr); // ['張三','李四','王五','趙六']
- 求的數(shù)組中的最大值和最小值
var arr = [1,8,5,4,5,9,6,3,7];
var maxValue = Math.max.apply(null,arr);
console.log(maxValue); // 9
var minValue = Math.min.apply(null,arr);
console.log(minValue); // 1