js中call、apply和bind到底有什麼區別?

介紹

在js中,每一個函數的原型都指向Function.prototype對象(js基於原型鏈的繼承)。所以,每一個函數都會有apply,call,和bind方法,這些方法繼承於Function。
它們的做用是同樣的,都是用來改變函數中this的指向。node

使用方法

apply的用法能夠表示以下:
A.apply(B, [x, y, z]);
此方法能夠改變函數A的this指向,使之指向函數B。第二個參數傳的是一個函數參數列表的數組形式。es6

call的用法和apply差很少,就只有傳參方式不同。相似於這樣 :
A.apply(B, x, y, z)
能夠把多個參數分開來傳,而不是像apply同樣,須要把全部參數放到一個數組裏邊傳進來。數組

bind的傳參方式和call同樣,只不過它的不一樣之處是,apply和call方法調用以後會當即執行,而bind方法調用以後會返回一個新的函數,它並不會當即執行,須要咱們手動執行。瀏覽器

舉例

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
  1. 當直接調用p1.func方法時,this指向的是當前p1這個對象,所以name和age都是它自己對象的屬性值。
  2. 當使用call方法,傳入的第一個參數爲空時,在瀏覽器環境下,this指向window;在node環境下,this指向global。讀者可自行把name和age改成global.name和global.age驗證一下。
  3. 使用apply方法時,把p2傳進去,至關於把函數的this指向p2對象,所以,此時打印出來的屬性都是p2對象的屬性
  4. 使用bind方法時,會生成一個新的函數對象,所以須要手動執行一下這個函數(即在函數末尾加個括號執行)。

總結

例子講完,call,apply和bind的區別就已經很清楚了。它們就是爲了改變this的上下文而存在。所以,有時候你會看到這樣的用法。爲了避免改變this的指向,一般會在函數後邊加上bind(this),以下app

function f(){}.bind(this)

這樣的話,就不會出現莫名其妙的this指向問題了。明明我想在函數裏邊調用此函數所屬對象的某個屬性時,爲何用this卻訪問不到呢。(寫js的新手確定會遇到過這種問題)函數

其實,從es6開始,已經支持箭頭函數了,我建議你們用箭頭函數,就不會出現this指向的問題了。this

另外,使用call,apply還能夠實現函數的繼承。在es6的class沒有出現以前,就須要藉助它們來實現繼承關係。prototype

相關文章
相關標籤/搜索