介紹
在js中,每個函數(shù)的原型都指向Function.prototype對象(js基于原型鏈的繼承)。因此,每個函數(shù)都會有apply,call,和bind方法,這些方法繼承于Function。
它們的作用是一樣的,都是用來改變函數(shù)中this的指向。
使用方法
apply的用法可以表示如下:
A.apply(B, [x, y, z]);
此方法可以改變函數(shù)A的this指向,使之指向函數(shù)B。第二個參數(shù)傳的是一個函數(shù)參數(shù)列表的數(shù)組形式。
call的用法和apply差不多,就只有傳參方式不一樣。類似于這樣 :
A.apply(B, x, y, z)
可以把多個參數(shù)分開來傳,而不是像apply一樣,需要把所有參數(shù)放到一個數(shù)組里邊傳進(jìn)來。
bind的傳參方式和call一樣,只不過它的不同之處是,apply和call方法調(diào)用之后會立即執(zhí)行,而bind方法調(diào)用之后會返回一個新的函數(shù),它并不會立即執(zhí)行,需要我們手動執(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方法時,this指向的是當(dāng)前p1這個對象,因此name和age都是它本身對象的屬性值。
- 當(dāng)使用call方法,傳入的第一個參數(shù)為空時,在瀏覽器環(huán)境下,this指向window;在node環(huán)境下,this指向global。讀者可自行把name和age改為global.name和global.age驗(yàn)證一下。
- 使用apply方法時,把p2傳進(jìn)去,相當(dāng)于把函數(shù)的this指向p2對象,因此,此時打印出來的屬性都是p2對象的屬性
- 使用bind方法時,會生成一個新的函數(shù)對象,因此需要手動執(zhí)行一下這個函數(shù)(即在函數(shù)末尾加個括號執(zhí)行)。
總結(jié)
例子講完,call,apply和bind的區(qū)別就已經(jīng)很清楚了。它們就是為了改變this的上下文而存在。因此,有時候你會看到這樣的用法。為了不改變this的指向,通常會在函數(shù)后邊加上bind(this),如下
function f(){}.bind(this)
這樣的話,就不會出現(xiàn)莫名其妙的this指向問題了。明明我想在函數(shù)里邊調(diào)用此函數(shù)所屬對象的某個屬性時,為什么用this卻訪問不到呢。(寫js的新手肯定會遇到過這種問題)
其實(shí),從es6開始,已經(jīng)支持箭頭函數(shù)了,我建議大家用箭頭函數(shù),就不會出現(xiàn)this指向的問題了。
另外,使用call,apply還可以實(shí)現(xiàn)函數(shù)的繼承。在es6的class沒有出現(xiàn)之前,就需要借助它們來實(shí)現(xiàn)繼承關(guān)系。