聊一聊call、apply、bind的區別

咱們都知道call apply bind均可以改變函數調用的this指向。那麼它們三者有什麼區別,何時該用哪一個呢?
咱們先直接經過代碼實例來了解,後面再借助專業文檔來解釋。javascript

舉個?

// 有隻貓叫小黑,小黑會吃魚
const cat = {
    name: '小黑',
    eatFish(...args) {
        console.log('this指向=>', this);
        console.log('...args', args);
        console.log(this.name + '吃魚');
    },
}
// 有隻狗叫大毛,大毛會吃骨頭
const dog = {
    name: '大毛',
    eatBone(...args) {
        console.log('this指向=>', this);
        console.log('...args', args);
        console.log(this.name + '吃骨頭');
    },
}

console.log('=================== call =========================');
// 有一天大毛想吃魚了,但是它不知道怎麼吃。怎麼辦?小黑說我吃的時候餵你吃
cat.eatFish.call(dog, '汪汪汪', 'call')
// 大毛爲了表示感謝,決定下次吃骨頭的時候也喂小黑吃
dog.eatBone.call(cat, '喵喵喵', 'call')

console.log('=================== apply =========================');
cat.eatFish.apply(dog, ['汪汪汪', 'apply'])
dog.eatBone.apply(cat, ['喵喵喵', 'apply'])

console.log('=================== bind =========================');
// 有一天他們以爲每次吃的時候再喂太麻煩了。乾脆直接教對方怎麼吃
const test1 = cat.eatFish.bind(dog, '汪汪汪', 'bind')
const test2 = dog.eatBone.bind(cat, '喵喵喵', 'bind')
test1()
test2()

clipboard.png

好了例子很簡單可是基本的使用方法跟場景都涉及到了。

callapply的用法幾乎同樣,惟一的不一樣就是傳遞的參數不一樣,call只能一個參數一個參數的傳入。
apply則只支持傳入一個數組,哪怕是一個參數也要是數組形式。最終調用函數時候這個數組會拆成一個個參數分別傳入。
至於bind方法,他是直接改變這個函數的this指向而且返回一個新的函數,以後再次調用這個函數的時候this都是指向bind綁定的第一個參數。bind傳餐方式跟call方法一致。java

因爲apply函數傳參的特殊性,咱們又衍生出了一個黑魔法。

// 若是一個數組咱們已知裏面全都是數字,想要知道最大的那個數,因爲Array沒有max方法,Math對象上有
// 咱們能夠根據apply傳遞參數的特性將這個數組當成參數傳入
// 最終Math.max函數調用的時候會將apply的數組裏面的參數一個一個傳入,剛好符合Math.max的參數傳遞方式
// 這樣變相的實現了數組的max方法。min方法也同理
const arr = [1,2,3,4,5,6]
const max = Math.max.apply(null, arr)
console.log(max)    // 6

這裏bind函數也有一個小技巧

// 若是你想將某個函數綁定新的`this`指向而且固定先傳入幾個變量能夠在綁定的時候就傳入,以後調用新函數傳入的參數都會排在以後
const obj = {}
function test(...args) {console.log(args)}
const newFn = test.bind(obj, '靜態參數1', '靜態參數2')
newFn('動態參數3', '動態參數4')

clipboard.png

接着來看看MDN文檔

call語法

  • fun.call(thisArg, arg1, arg2, ...)
  • thisArg: 在fun函數運行時指定的this值。須要注意的是,指定的this值並不必定是該函數執行時真正的this值,若是這個函數處於非嚴格模式下,則指定爲null和undefined的this值會自動指向全局對象(瀏覽器中就是window對象),同時值爲原始值(數字,字符串,布爾值)的this會指向該原始值的自動包裝對象。
  • arg1, arg2, ... 指定的參數列表

apply語法

  • fun.apply(thisArg, [argsArray])
  • thisArg 在 fun 函數運行時指定的 this 值。須要注意的是,指定的 this 值並不必定是該函數執行時真正的 this 值,若是這個函數處於非嚴格模式下,則指定爲 null 或 undefined 時會自動指向全局對象(瀏覽器中就是window對象),同時值爲原始值(數字,字符串,布爾值)的 this 會指向該原始值的自動包裝對象。
  • argsArray 一個數組或者類數組對象,其中的數組元素將做爲單獨的參數傳給 fun 函數。若是該參數的值爲null 或 undefined,則表示不須要傳入任何參數。從ECMAScript 5 開始可使用類數組對象。

bind語法

  • fun.bind(thisArg[, arg1[, arg2[, ...]]])
  • thisArg 當綁定函數被調用時,該參數會做爲原函數運行時的 this 指向。當使用new 操做符調用綁定函數時,該參數無效。
  • arg1, arg2, ... 當綁定函數被調用時,這些參數將置於實參以前傳遞給被綁定的方法。

總結

  1. 當咱們使用一個函數須要改變this指向的時候纔會用到call`apply`bind
  2. 若是你要傳遞的參數很少,則可使用fn.call(thisObj, arg1, arg2 ...)
  3. 若是你要傳遞的參數不少,則能夠用數組將參數整理好調用fn.apply(thisObj, [arg1, arg2 ...])
  4. 若是你想生成一個新的函數長期綁定某個函數給某個對象使用,則可使用const newFn = fn.bind(thisObj); newFn(arg1, arg2...)
相關文章
相關標籤/搜索