介紹
在js中采缚,每個(gè)函數(shù)的原型都指向Function.prototype對(duì)象(js基于原型鏈的繼承)针炉。因此,每個(gè)函數(shù)都會(huì)有apply扳抽,call篡帕,和bind方法,這些方法繼承于Function贸呢。
它們的作用是一樣的镰烧,都是用來(lái)改變函數(shù)中this的指向。
使用方法
apply的用法可以表示如下:
A.apply(B, [x, y, z]);
此方法可以改變函數(shù)A的this指向楞陷,使之指向函數(shù)B怔鳖。第二個(gè)參數(shù)傳的是一個(gè)函數(shù)參數(shù)列表的數(shù)組形式。
call的用法和apply差不多固蛾,就只有傳參方式不一樣结执。類(lèi)似于這樣 :
A.apply(B, x, y, z)
可以把多個(gè)參數(shù)分開(kāi)來(lái)傳,而不是像apply一樣魏铅,需要把所有參數(shù)放到一個(gè)數(shù)組里邊傳進(jìn)來(lái)昌犹。
bind的傳參方式和call一樣,只不過(guò)它的不同之處是览芳,apply和call方法調(diào)用之后會(huì)立即執(zhí)行斜姥,而bind方法調(diào)用之后會(huì)返回一個(gè)新的函數(shù),它并不會(huì)立即執(zhí)行沧竟,需要我們手動(dòng)執(zhí)行铸敏。
舉例
var name = "佚名";
var age = 20;
//global.name
//global.age
var p1 = {
name: "張三",
age: 12,
func: function(){
console.log(`姓名:${this.name},年齡:${this.age}`)
}
}
var p2 = {
name: "李四",
age: 15
}
p1.func(); //姓名:張三,年齡:12
p1.func.call(); //姓名:佚名,年齡:20
p1.func.apply(p2); //姓名:李四,年齡:15
p1.func.bind(p2)(); //姓名:李四,年齡:15
- 當(dāng)直接調(diào)用p1.func方法時(shí),this指向的是當(dāng)前p1這個(gè)對(duì)象悟泵,因此name和age都是它本身對(duì)象的屬性值杈笔。
- 當(dāng)使用call方法,傳入的第一個(gè)參數(shù)為空時(shí)糕非,在瀏覽器環(huán)境下蒙具,this指向window;在node環(huán)境下朽肥,this指向global禁筏。讀者可自行把name和age改為global.name和global.age驗(yàn)證一下。
- 使用apply方法時(shí)衡招,把p2傳進(jìn)去篱昔,相當(dāng)于把函數(shù)的this指向p2對(duì)象,因此,此時(shí)打印出來(lái)的屬性都是p2對(duì)象的屬性
- 使用bind方法時(shí)州刽,會(huì)生成一個(gè)新的函數(shù)對(duì)象空执,因此需要手動(dòng)執(zhí)行一下這個(gè)函數(shù)(即在函數(shù)末尾加個(gè)括號(hào)執(zhí)行)。
總結(jié)
例子講完穗椅,call辨绊,apply和bind的區(qū)別就已經(jīng)很清楚了。它們就是為了改變this的上下文而存在房待。因此邢羔,有時(shí)候你會(huì)看到這樣的用法。為了不改變this的指向桑孩,通常會(huì)在函數(shù)后邊加上bind(this)拜鹤,如下
function f(){}.bind(this)
這樣的話,就不會(huì)出現(xiàn)莫名其妙的this指向問(wèn)題了流椒。明明我想在函數(shù)里邊調(diào)用此函數(shù)所屬對(duì)象的某個(gè)屬性時(shí)敏簿,為什么用this卻訪問(wèn)不到呢。(寫(xiě)js的新手肯定會(huì)遇到過(guò)這種問(wèn)題)
其實(shí)宣虾,從es6開(kāi)始惯裕,已經(jīng)支持箭頭函數(shù)了,我建議大家用箭頭函數(shù)绣硝,就不會(huì)出現(xiàn)this指向的問(wèn)題了蜻势。
另外,使用call鹉胖,apply還可以實(shí)現(xiàn)函數(shù)的繼承握玛。在es6的class沒(méi)有出現(xiàn)之前,就需要借助它們來(lái)實(shí)現(xiàn)繼承關(guān)系甫菠。