開(kāi)始看到JavaScript中的apply和call函數(shù)靶溜,非常不解绑谣。也看過(guò)幾篇文章但是一到實(shí)踐用到的時(shí)候又遺忘了。本文結(jié)合實(shí)例搏予,當(dāng)做筆記記錄一下該問(wèn)題與大家分享。
apply:方法能劫持另外一個(gè)對(duì)象的方法葫哗,繼承另外一個(gè)對(duì)象的屬性.(具體是什么意思呢缔刹?我們看看下面的例子就知道啦)
1.apply()和call()基本認(rèn)識(shí)
apply()在w3c手冊(cè)是這樣描述的:
方法重用
通過(guò) apply() 方法,您能夠編寫(xiě)用于不同對(duì)象的方法劣针。
call() 和 apply() 之間的區(qū)別
不同之處是:
call() 方法分別接受參數(shù)校镐。
apply() 方法接受數(shù)組形式的參數(shù)。
如果要使用數(shù)組而不是參數(shù)列表捺典,則 apply() 方法非常方便鸟廓。
簡(jiǎn)單的來(lái)說(shuō),call()是apply()的一顆語(yǔ)法糖襟己,作用和 apply() 一樣引谜,同樣可實(shí)現(xiàn)繼承,唯一的區(qū)別就在于call()接收的是參數(shù)列表擎浴,而apply()則接收參數(shù)數(shù)組员咽。
一個(gè)簡(jiǎn)單的實(shí)例,希望大家也可以理解數(shù)據(jù)的關(guān)系贮预,文末還有一個(gè)小問(wèn)題贝室,知道答案的話也就基本理解了apply啦契讲。
2.apply()和call()使用
使用 apply, 你可以繼承其他對(duì)象的方法:
var max = Math.max.apply(null, [1, 2, 3, 4, 5]);
console.log(max); // 輸出5
注意這里apply()的第一個(gè)參數(shù)是null滑频,在非嚴(yán)格模式下捡偏,第一個(gè)參數(shù)為null或者undefined時(shí)會(huì)自動(dòng)替換為指向全局對(duì)象,apply()的第二個(gè)參數(shù)為數(shù)組或類數(shù)組峡迷。
使用call:
var max = Math.max.call(null, 1, 2, 3, 4, 5);
console.log(max); // 輸出5
來(lái)看w3c上的示例:
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"John",
lastName: "Doe"
}
person.fullName.apply(person1, ["Oslo", "Norway"]);
// person.fullName.call(person1, "Oslo", "Norway"); // call
以上代碼的結(jié)果是
再看兩個(gè)小例子:
(本例子在vue項(xiàng)目中實(shí)現(xiàn))
例1:
test.vue 頁(yè)面上寫(xiě)一個(gè)按鈕 按鈕點(diǎn)擊觸發(fā) btnclick()彤避,我們可以看到在方法內(nèi)有一個(gè)person類,有一個(gè)student類看杭。對(duì)比控制臺(tái)輸出忠藤,我們可以發(fā)現(xiàn)挟伙。
最后一行''444444'輸出的this楼雹,是vue對(duì)象〖饫可以理解
student內(nèi)的this贮缅,是當(dāng)前student對(duì)象。也可以理解
person內(nèi)的this介却,就是student對(duì)象谴供。 為什么?
原因是因?yàn)樵趕tudent內(nèi)apply的使用Person.apply(this,arguments)齿坷。此時(shí)person.apply把student內(nèi)當(dāng)前對(duì)象劫持并繼承該對(duì)象
apply:方法能劫持另外一個(gè)對(duì)象的方法桂肌,繼承另外一個(gè)對(duì)象的屬性.
btnclick () {
function Person (name, age) {
console.log(name, age, '1111111111111') // 控制臺(tái)輸出 jack 24 1111111111111
console.log(this, '33333333333') // 控制臺(tái)輸出 Student {} "33333333333"
this.name = name
this.age = age
}
function Student (name, age, grade)
{
Person.apply(this,arguments)
console.log(this) // 控制臺(tái)輸出 Student {name: "jack", age: 24}
console.log(arguments) // 控制臺(tái)輸出 Arguments(3) ["jack", 24, "2年"]
this.grade = grade;
}
const stu = new Student("jack", 24, "2年")
console.log(stu, '2222222222') // 控制臺(tái)輸出 Student {name: "jack", age: 24, grade: "2年"} "2222222222"
console.log(this, '4444444444') // 控制臺(tái)輸出 VueComponent {_uid: 9, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …} "4444444444"
}
?例2:
test.vue 頁(yè)面上寫(xiě)一個(gè)按鈕 按鈕點(diǎn)擊觸發(fā) btnclick2(),我們可以看到在方法內(nèi)只有一個(gè)person類永淌。對(duì)比控制臺(tái)輸出崎场,我們可以發(fā)現(xiàn)。
person內(nèi)的this輸出為當(dāng)前vue對(duì)象遂蛀,與上面對(duì)比的不同之處在于谭跨,例1中的person.apply()是在student內(nèi)使用的,而當(dāng)前例子的person.apply()是在點(diǎn)擊按鈕方法內(nèi)直接觸發(fā)的李滴,所以對(duì)象this也就變成了當(dāng)前對(duì)象this螃宙,即vue實(shí)例。
btnclick2 () {
function Person (name, age) {
console.log(name, age, '1111111111111') // 控制臺(tái)輸出 jack 18 1111111111111
console.log(this, '33333333333') // VueComponent {_uid: 9, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …} "33333333333"
this.name = name
this.age = age
}
const params = ["jack", 18]
Person.apply(this,params)
console.log(this) // VueComponent {_uid: 9, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
}
?補(bǔ)充:
整文件代碼如下所坯,可以看到頁(yè)面還會(huì)輸出name,age,grade谆扎。
<template>
<div class="hello">
<div>
<button @click="btnclick()">觸發(fā)函數(shù)</button>
<button @click="btnclick2()">觸發(fā)函數(shù)2</button>
</div>
<div>{{ name }}</div>
<div>{{ age }}</div>
<div>{{ grade }}</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
data () {
return {
name: '',
age: '',
grade: ''
}
},
methods: {
btnclick () {
function Person (name, age) {
console.log(name, age, '1111111111111')
console.log(this, '33333333333')
this.name = name
this.age = age
}
function Student (name, age, grade)
{
Person.apply(this,arguments)
console.log(this)
console.log(arguments)
this.grade = grade;
}
const stu = new Student("jack", 24, "2年")
console.log(stu, '2222222222')
console.log(this, '4444444444')
},
btnclick2 () {
function Person (name, age) {
console.log(name, age, '1111111111111')
console.log(this, '33333333333')
this.name = name
this.age = age
}
const params = ["jack", 18]
Person.apply(this,params)
console.log(this)
}
}
}
</script>
<style scoped>
</style>
問(wèn):為什么點(diǎn)擊第一個(gè)按鈕時(shí),頁(yè)面無(wú)變化芹助。點(diǎn)擊第二個(gè)按鈕時(shí)堂湖,頁(yè)面顯示name籍凝,age?
如何選用:
- 如果不需要關(guān)心具體有多少參數(shù)被傳入函數(shù)苗缩,選用apply()
- 如果確定函數(shù)可接收多少個(gè)參數(shù)饵蒂,并且想一目了然表達(dá)形參和實(shí)參的對(duì)應(yīng)關(guān)系,用call()
總結(jié)
- call()和apply()都是用來(lái)改變函數(shù)執(zhí)行時(shí)的上下文酱讶,可借助它們實(shí)現(xiàn)繼承退盯;
- call()和apply()唯一區(qū)別是參數(shù)不一樣,call()是apply()的語(yǔ)法糖
這兩個(gè)方法很好地體現(xiàn)了js函數(shù)式語(yǔ)言特性泻肯,在js中幾乎每一次編寫(xiě)函數(shù)式語(yǔ)言風(fēng)格的代碼渊迁,都離不開(kāi)call和apply,能夠熟練運(yùn)用它們灶挟,是真正成為一名jser程序員的重要一步琉朽。
本文在本人原始地址: 超人思否