js中call、bind、apply你知多少?

@TOCjavascript

在咱們平常開發過程當中call、bind、apply無疑是咱們用的比較多的語法,今天在開發中看到有同事傻傻分不清call和bind的區別,故在解釋一通以後,寫下此文;java

首先查看文檔理解含義

call()

MDN 文檔 call咱們能夠了解到: call() 方法使用一個指定的 this 值和單獨給出的一個或多個參數來調用一個函數。git

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

先舉個例子:github

// main.js
  const foo={
      name:'foo',
      getFoo(...args){
        console.log('this===',this,'this.name==',this.name)
        console.log('-----------------------------------')
        console.log('...args=====',...args)
      }
    }
    const bar={
      name:'bar',
      getBar(...args){
        console.log('this===',this,'this.name==',this.name)
        console.log('-----------------------------------')
        console.log('...args=====',...args)
      }
    }
    foo.getFoo() //this=== {name: "foo", getFoo: ƒ} this.name== foo ----------------------------------- ...args=====
    bar.getBar() //this=== {name: "bar", getBar: ƒ} this.name== bar ----------------------------------- ...args=====

複製代碼

假如咱們想在getFoo去借bar裏面的東西用用,該怎麼辦呢? 也許有同窗想到的是這樣:數組

foo.getFoo(bar.name) // this=== {name: "foo", getFoo: ƒ} this.name== foo ----------------------------------- ...args===== bar

複製代碼

毫無疑問,這是沒問題的,但此時只是正常的傳參,可否乾脆點把this.name也改爲bar呢;根據call的定義:瀏覽器

foo.getFoo.call(bar,'測試傳參','測試call') //his=== {name: "bar", getBar: ƒ} this.name== bar ----------------------------------- ...args===== 測試傳參 測試call
//使用call後,咱們能夠看到foo.getFoo的this此時指向了bar對象,此時的name拿到的bar的對象的name;
複製代碼

apply()

MDN 文檔 apply咱們能夠了解到: apply() 方法調用一個具備給定this值的函數,以及做爲一個數組(或相似數組對象)提供的參數。app

  • func.apply(thisArg, [argsArray])ide

  • thisArg:可選的。在 func 函數運行時使用的 this 值。請注意,this可能不是該方法看到的實際值:若是這個函數處於非嚴格模式下,則指定爲 nullundefined 時會自動替換爲指向全局對象,原始值會被包裝。函數

  • argsArray:可選的。一個數組或者類數組對象,其中的數組元素將做爲單獨的參數傳給 func 函數。若是該參數的值爲 nullundefined,則表示不須要傳入任何參數。從ECMAScript 5 開始可使用類數組對象。 瀏覽器兼容性 請參閱本文底部內容。測試

繼續使用剛纔的foo和bar

foo.getFoo.apply(bar,['測試傳參','測試apply']) //his=== {name: "bar", getBar: ƒ} this.name== bar ----------------------------------- ...args===== 測試傳參 測試apply

複製代碼

總結 call方法和apply方法二者極度類似,區別就是call()方法接受的是參數列表,而apply()方法接受的是一個參數數組。

bind()

MDN 文檔 bind咱們能夠了解到:

bind()方法建立一個新的函數,在調用時設置this關鍵字爲提供的值。並在調用新函數時,將給定參數列表做爲原函數的參數序列的前若干項。

  • function.bind(thisArg[, arg1[, arg2[, ...]]])

  • thisArg 調用綁定函數時做爲this參數傳遞給目標函數的值。 若是使用new運算符構造綁定函數,則忽略該值。當使用bindsetTimeout中建立一個函數(做爲回調提供)時,做爲thisArg傳遞的任何原始值都將轉換爲object。若是bind函數的參數列表爲空,執行做用域的this將被視爲新函數的thisArg

  • arg1, arg2, ... 當目標函數被調用時,預先添加到綁定函數的參數列表中的參數。

emmmm...繼續最最上面的那個foo和bar

foo.getFoo.bind(bar,'測試傳參','測試bind') // 此時是無輸出,由於bind()方法建立一個新的函數,當前函數並無執行


複製代碼

修改以下:

const foobindbar = foo.getFoo.bind(bar,'測試傳參','測試bind');

console.log(foobindbar)
    // ƒ getFoo(...args){
    // console.log('this===',this,'this.name==',this.name)
    // console.log('-----------------------------------')
    // console.log('...args=====',...args)
    // }

foobindbar() //this=== {name: "bar", getBar: ƒ} this.name== bar ----------------------------------- ...args===== 測試傳參 測試apply


複製代碼

總結

call和apply的區別

call方法和apply方法二者極度類似,區別就是call()方法接受的是參數列表,而apply()方法接受的是一個參數數組。用apply時,即便傳入的參數只有一個,也必須定義爲數組才行;

call與apply 和 bind的區別

call與apply改變this的指向時,會直接觸發函數;而bind會建立一個新的函數,在調用時設置this關鍵字爲提供的值,使用bind時,會優先使用bind綁定的幾個值; 以下:

foo.getFoo.bind(bar,'測試傳參','測試bind')
const foobindbar = foo.getFoo.bind(bar,'測試傳參','測試bind');

console.log(foobindbar)
    // ƒ getFoo(...args){
    // console.log('this===',this,'this.name==',this.name)
    // console.log('-----------------------------------')
    // console.log('...args=====',...args)
    // }

foobindbar('參數1', '參數2') //this=== {name: "bar", getBar: ƒ} this.name== bar ----------------------------------- ...args===== 測試傳參 測試apply 參數1 參數2
// ...args===== 測試傳參 測試apply 參數1 參數2

複製代碼

文章所示demo請轉王一諾/github

相關文章
相關標籤/搜索