大家好,我是IT修真院萌新分院第3期的學(xué)員張曉琳,一枚正直、純潔、善良的前端程序員今天給大家分享一下,修真院官網(wǎng)js任務(wù)2深度思考中的知識(shí)點(diǎn)——如何理解js中call和apply?
1.背景介紹
call 和 apply 都是為了改變某個(gè)函數(shù)運(yùn)行時(shí)的?
context 即上下文而存在的,換句話說(shuō),
就是為了改變函數(shù)體內(nèi)部 this 的指向。
因?yàn)?JavaScript 的函數(shù)存在
「定義時(shí)上下文」和「運(yùn)行時(shí)上下文」
以及「上下文是可以改變的」這樣的概念。
2.知識(shí)剖析
1. apply:?
方法能劫持另外一個(gè)對(duì)象的方法,繼承另外一個(gè)對(duì)象的屬性.?
Function.apply(obj,args)方法能接收兩個(gè)參數(shù)
obj:這個(gè)對(duì)象將代替Function類(lèi)里this對(duì)象
args:這個(gè)是數(shù)組,它將作為參數(shù)傳給Function(args-->arguments)
2. call?
和apply的意思一樣,只不過(guò)是參數(shù)列表不一樣
Function.call(obj,[param1[,param2[,…[,paramN] ] ] ] )
obj:這個(gè)對(duì)象將代替Function類(lèi)里this對(duì)象
params:這個(gè)是一個(gè)參數(shù)列表
3.常見(jiàn)問(wèn)題
如何使用call和apply?
4.解決方案
call 和 apply 的作用基本類(lèi)似,?
都是去執(zhí)行function并將這個(gè)function?
的context替換成第一個(gè)參數(shù)帶入。?
兩者的不同是call 必須將function 的參數(shù)一一帶入,接受的是連續(xù)參數(shù)
而 apply 接受的是數(shù)組參數(shù) 只要在第二個(gè)參數(shù)帶入一個(gè)數(shù)列。
//j? k? 形參
function add(j, k) {
? ? return j + k;
}
function sub(j, k) {
? ? return j - k;
}
// 5 3? 實(shí)參
add(5, 3); //8
add.call(sub, 5, 3); //8
add.apply(sub, [5, 3]); //8
sub(5, 3); //2
sub.call(add, 5, 3); //2
sub.apply(add, [5, 3]); //2
//通過(guò)call和apply實(shí)現(xiàn)對(duì)象繼承。
var Parent = function () {
? ? this.name = "yjc";
? ? this.age = 22;
}
var child = {};
console.log(child);//Object {} ,空對(duì)象
Parent.call(child);
console.log(child); //Object {name: "yjc", age: 22}
//call方法1
window.color = 'red';
document.color = 'yellow';
var s1 = {color: 'blue' };
function changeColor(){
? ? console.log(this.color);
}
//2
changeColor.call();? ? ? ? //red (默認(rèn)傳遞參數(shù))
changeColor.call(window);? //red
changeColor.call(document); //yellow
changeColor.call(this);? ? //red
changeColor.call(s1);? ? ? //blue
var Pet = {
? ? words : '...',
? ? speak : function (say) {
? ? ? ? console.log(say + ''+ this.words)
}
}
Pet.speak('Speak'); // 結(jié)果:Speak...
var Dog = {
? ? words:'Wang'
}
//將this的指向改變成了Dog
Pet.speak.call(Dog, 'Speak'); //結(jié)果:SpeakWang
//apply方法1
window.number = 'one';
document.number = 'two';
var s1 = {number: 'three' };
function changeColor(){
? ? console.log(this.number);
}
changeColor.apply();? ? ? ? //one (默認(rèn)傳參)
changeColor.apply(window);? //one
changeColor.apply(document); //two
changeColor.apply(this);? ? //one
changeColor.apply(s1);? ? ? //three
//方法2
function Pet(words){
? ? this.words = words;
? ? this.speak = function () {
? ? ? ? console.log( this.words)
}
}
function Dog(words){
? ? //Pet.call(this, words); //結(jié)果:Wang
? ? Pet.apply(this, arguments); //結(jié)果:Wang
}
var dog = new Dog('Wang');
dog.speak();
5.編碼實(shí)戰(zhàn)
// call方法可以用來(lái)代替另一個(gè)對(duì)象調(diào)用一個(gè)方法,
// call方法可以將一個(gè)函數(shù)的對(duì)象上下文從初始的上下文改變?yōu)閠hisObj指定的新對(duì)象,
// 如果沒(méi)有提供thisObj參數(shù),那么Global對(duì)象被用于thisObj。
//1:
? ? function add(c,d){
? ? ? ? return this.a + this.b + c + d;
}
var s = {a:1, b:2};
console.log(add.call(s,3,4)); // 1+2+3+4 = 10
console.log(add.apply(s,[5,6])); // 1+2+5+6 = 14
//2:
window.firstName = "Cynthia";
window.lastName = "_xie";
var myObject = {firstName:'my', lastName:'Object'};
function getName(){
? ? console.log(this.firstName + this.lastName);
}
function getMessage(sex,age){
? ? console.log(this.firstName + this.lastName + " 性別: " + sex + " age: " + age );
}
getName.call(window); // Cynthia_xie
getName.call(myObject); // myObject
getName.apply(window); // Cynthia_xie
getName.apply(myObject);// myObject
getMessage.call(window,"女",21); //Cynthia_xie 性別: 女a(chǎn)ge: 21
getMessage.apply(window,["女",21]); // Cynthia_xie 性別: 女a(chǎn)ge: 21
getMessage.call(myObject,"未知",22); //myObject 性別: 未知age: 22
getMessage.apply(myObject,["未知",22]); // myObject 性別: 未知 age: 22
6.擴(kuò)展思考
call()和apply()兩種方法的區(qū)別??
相同點(diǎn):兩個(gè)方法產(chǎn)生的作用是完全一樣的
不同點(diǎn):方法傳遞的參數(shù)不同
call()接受的是一個(gè)參數(shù)列表,而apply()接受一個(gè)參數(shù)數(shù)組。
func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])
其中 this 是你想指定的上下文,他可以是任何一個(gè) JavaScript 對(duì)象(JavaScript 中一切皆對(duì)象),
call 需要把參數(shù)按順序傳遞進(jìn)去,而 apply 則是把參數(shù)放在數(shù)組里。
因此要說(shuō)適用條件的話,當(dāng)你的參數(shù)是明確知道數(shù)量時(shí)用 call 。
而不確定的時(shí)候用 apply,然后把參數(shù) push 進(jìn)數(shù)組傳遞進(jìn)去。
7.參考文獻(xiàn)
8.更多討論
問(wèn)題:
Q1:王姣妍:是call還是apply能改變this的指向?
A1:張曉琳:兩個(gè)都能改,就是傳參數(shù)方式不一樣呀,apply傳數(shù)組,call傳字符串。
Q2:王棟:apply的應(yīng)用場(chǎng)景呢??
A2:其他人:
我首先從網(wǎng)上查到關(guān)于apply和call的定義,然后用示例來(lái)解釋這兩個(gè)方法的意思和如何去用.??
?????????apply:方法能劫持另外一個(gè)對(duì)象的方法,繼承另外一個(gè)對(duì)象的屬性.??
?Function.apply(obj,args)方法能接收兩個(gè)參數(shù)??
obj:這個(gè)對(duì)象將代替Function類(lèi)里this對(duì)象??
args:這個(gè)是數(shù)組,它將作為參數(shù)傳給Function(args-->arguments)??
?????????call:和apply的意思一樣,只不過(guò)是參數(shù)列表不一樣.??
?Function.call(obj,[param1[,param2[,…[,paramN]]]])??
obj:這個(gè)對(duì)象將代替Function類(lèi)里this對(duì)象??
params:這個(gè)是一個(gè)參數(shù)列表??
1.apply示例:??
/*定義一個(gè)人類(lèi)*/???
function?Person(name,age)?{???
this.name=name;?this.age=age;???
}???
/*定義一個(gè)學(xué)生類(lèi)*/???
functionStudent(name,age,grade)?{???
Person.apply(this,arguments);?this.grade=grade;???
}???
//創(chuàng)建一個(gè)學(xué)生類(lèi)???
var?student=new?Student("qian",21,"一年級(jí)");???
//測(cè)試???
alert("name:"+student.name+"\n"+"age:"+student.age+"\n"+"grade:"+student.grade);???
//大家可以看到測(cè)試結(jié)果name:qian?age:21?grade:一年級(jí)???
//學(xué)生類(lèi)里面我沒(méi)有給name和age屬性賦值啊,為什么又存在這兩個(gè)屬性的值呢,這個(gè)就是apply的神奇之處.? ?
分析:?Person.apply(this,arguments);??
this:在創(chuàng)建對(duì)象在這個(gè)時(shí)候代表的是student??
arguments:是一個(gè)數(shù)組,也就是[“qian”,”21”,”一年級(jí)”];??
也就是通俗一點(diǎn)講就是:用student去執(zhí)行Person這個(gè)類(lèi)里面的內(nèi)容,在Person這個(gè)類(lèi)里面存在this.name等之類(lèi)的語(yǔ)句,這樣就將屬性創(chuàng)建到了student對(duì)象里面?
Q3:王棟:call的應(yīng)用場(chǎng)景呢??
A3:其他人:在給對(duì)象參數(shù)的情況下,如果參數(shù)的形式是數(shù)組的時(shí)候,比如apply示例里面?zhèn)鬟f了參數(shù)arguments,這個(gè)參數(shù)是數(shù)組類(lèi)型,并且在調(diào)用Person的時(shí)候參數(shù)的列表是對(duì)應(yīng)一致的(也就是Person和Student的參數(shù)列表前兩位是一致的)?就可以采用?apply?,?如果我的Person的參數(shù)列表是這樣的(age,name),而Student的參數(shù)列表是(name,age,grade),這樣就可以用call來(lái)實(shí)現(xiàn)了,也就是直接指定參數(shù)列表對(duì)應(yīng)值的位置(Person.call(this,age,name,grade));?
如何理解js中call和apply視頻