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

介紹

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

使用方法

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

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),如下

function f(){}.bind(this)

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

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

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章