如何理解js中的call和apply?

如何理解 js 中的 call 和 apply?

背景介紹

call 和 apply 都是為了改變某個(gè)函數(shù)運(yùn)行時(shí)的 context 即上下文而存在的

換句話說(shuō),就是為了改變函數(shù)體內(nèi)部 this 的指向。因?yàn)?JavaScript 的函數(shù)存在「定義時(shí)上下文」和「運(yùn)行時(shí)上下文」以及「上下文是可以改變的」這樣的概念。

知識(shí)剖析

apply

方法能劫持另外一個(gè)對(duì)象的方法,繼承另外一個(gè)對(duì)象的屬性. Function.apply(obj,args)方法能接收兩個(gè)參數(shù)

obj:這個(gè)對(duì)象將代替 Function 類里 this 對(duì)象

args:這個(gè)是數(shù)組,它將作為參數(shù)傳給 Function(args-->arguments)

call

和 apply 的意思一樣,只不過(guò)是參數(shù)列表不一樣

Function.call(obj,[param1[,param2[,…[,paramN] ] ] ] )

obj:這個(gè)對(duì)象將代替 Function 類里 this 對(duì)象

params:這個(gè)是一個(gè)參數(shù)列表

常見(jiàn)問(wèn)題

如何使用 call 和 apply?

解決方案

call 和 apply 的作用基本類似,都是去執(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();

實(shí)例

// 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

拓展

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)去。

參考文檔

參考

Q&A

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 類里 this 對(duì)象

args:這個(gè)是數(shù)組,它將作為參數(shù)傳給 Function(args-->arguments), call:和 apply 的意思一樣,只不過(guò)是參數(shù)列表不一樣.

Function.call(obj,[param1[,param2[,…[,paramN]]]])

obj:這個(gè)對(duì)象將代替 Function 類里 this 對(duì)象

params:這個(gè)是一個(gè)參數(shù)列表

apply 示例

/*定義一個(gè)人類*/
function Person(name,age) {
this.name=name; this.age=age;
}

/*定義一個(gè)學(xué)生類*/
functionStudent(name,age,grade) {
Person.apply(this,arguments); this.grade=grade;
}

//創(chuàng)建一個(gè)學(xué)生類
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é)生類里面我沒(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è)類里面的內(nèi)容,在 Person 這個(gè)類里面存在 this.name 等之類的語(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ù)組類型,并且在調(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));

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容