1. 程式人生 > >清晰明瞭搞懂 call、apply、bind 的區別

清晰明瞭搞懂 call、apply、bind 的區別

文章目錄


直接來看 call 例子:
var People = {
  sayHello: function(arg1) {
    console.log('你好,' + this.name + ',' + arg1)
  }
}
var me = {
  name: 'Neveryu'
}
People.sayHello.call(me, '很高興見到你')  // 你好,Neveryu,很高興見到你

再來看 apply 例子:

var People = {
  sayHello: function(arg1) {
    console.log('你好,' + this.name + ',' + arg1)
  }
}
var me = {
  name: 'Neveryu'
}
People.sayHello.apply(me, ['很高興見到你'])  // 你好,Neveryu,很高興見到你

結果都相同。從寫法上我們就能看出二者之間的異同。相同之處在於,第一個引數都是要繫結的上下文,後面的引數是要傳遞給呼叫該方法的函式的。
不同之處在於,call 方法傳遞給呼叫函式的引數是逐個列出的,而 apply 則是要寫在陣列中。

核心要點: 可以看出 call 和 apply 是為了動態改變 this 而出現的,當一個 Object 沒有某個方法,但是呢,其它的物件有,我們可以藉助 call 或 apply 用其它物件的方法來操作。(用別人的,好過分啊~~)

實際用例:
舉一個在實際中會用到的例子吧:

我們知道,通過 document.getElementsByTagName 選擇的 dom 節點是一種類似 array 的 array 。它不能應用 Array 下的 push、pop 等方法。我們可以通過:

var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"))

這樣 domNodes 就可以應用 Array 下的所有方法了。

上面這 5 行內容是啥意思??
首先,document.getElementsByTagName("*") 得到的是一個 NodeList。【可以參考這裡:getElementsByTagName() 方法】它是一個 array-like object,常見的 array-link object 有:argumentsnodelist。他們不是陣列,不能使用陣列的一些方法。

var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*")) 就是將陣列的 slice 方法呼叫的主體變成了這個 document.getElementsByTagName("*")document.getElementsByTagName("*") 使用 slice 方法後會發生什麼呢?去熟悉一個 slice 的意思後,你就會知道它會返回一個數組。那麼我們得到的 domNodes 就是一個 document.getElementsByTagName("*") 的陣列了,就可以使用陣列的所有方法咯!~

再來看 bind 例子:

var People = {
  sayHello: function(arg1) {
    console.log('你好,' + this.name + ',' + arg1)
  }
}
var me = {
  name: 'Neveryu'
}
People.sayHello.bind(me, '很高興見到你')()  // 你好,Neveryu,很高興見到你
People.sayHello.bind(me, ['很高興見到你'])()  // 你好,Neveryu,很高興見到你

bind 方法傳遞給呼叫函式的引數可以逐個列出,也可以寫在陣列中。bind 方法與 call、apply 最大的不同就是前者返回一個繫結上下文的函式,而後者是直接執行了函式。由於這個原因,上面的程式碼也可以這樣寫:

var People = {
  sayHello: function(arg1) {
    console.log('你好,' + this.name + ',' + arg1)
  }
}
var me = {
  name: 'Neveryu'
}
People.sayHello.bind(me)('很高興見到你')  // 你好,Neveryu,很高興見到你
People.sayHello.bind(me)(['很高興見到你'])  // 你好,Neveryu,很高興見到你

bind 方法還可以這樣寫 fn.bind(obj, arg1)(arg2)

用一句話總結 bind 的用法:該方法建立一個新函式,稱為繫結函式,繫結函式會以建立它時傳入 bind 方法的第一個引數作為 this,傳入 bind 方法的第二個以及以後的引數加上繫結函式執行時本身的引數按照順序作為原函式的引數來呼叫原函式。