淺談JavaScript中的apply、call和bind

摘要

  • 三種方法都可改變函數this關鍵字的指向。
  • apply()接受一參數數組,返回函數執行的結果。
  • call()接受一組參數,返回函數執行的結果。
  • bind()接受一組參數,返回函數體。需在bind()後加小括號才能執行函數。
  • 箭頭函數的this綁定後不管使用apply()call()仍是bind()都不可修改。

淺析this關鍵字

  • JavaScript中的函數存在定義上下文運行上下文,經過call()apply()bind()能夠改變this的指向。
  • this總指向運行上下文

定義上下文

定義上下文更準確的名稱應該叫詞法做用域,它指函數的定義部分所造成的做用域。javascript

function fun1 () {
	// 函數fun1的詞法做用域
	// 函數定義
	// ....
}
複製代碼

運行上下文

函數在調用時會產生一個調用記錄,其中包含函數在哪裏被調用、傳入函數的參數等信息。該記錄也被稱爲運行上下文。一個函數的this總指向函數的運行上下文。當fun1fun2中調用時,fun1this指向fun2的定義上下文(詞法做用域)。java

function fun2 () {
    // fun1的this指向該做用域
    fun1();
    // 函數定義
    // ...
}
複製代碼

this的指向

this是運行上下文的一個屬性,所以常說this指向函數的運行上下文
this是在函數調用時被綁定的,與函數的聲明位置(即詞法做用域)沒有任何關係。數組


call()apply()

call()

call()方法的第一個參數爲要指定的this對象,第二個參數及之後爲函數運行所需的參數列表。app

let obj = {
    a: 1
}

function fun1 (num1, num2) {
    console.log(this); // obj {a: 1}
    console.log(num1 + num2); // 3
    console.log(this.a); // 1
}

fun1.call(obj, 1, 2);
複製代碼

上述代碼展現了call()的兩種能力。一方面它改變了fun1調用時的this關鍵字,讓其指向obj,並經過this關鍵字來訪問obj中的屬性。另外一方面它將本身接受到的參數傳入fun1函數

apply()

call()apply()本質上並沒有太大差異,惟一的區別在於call()接受的是參數列表,而apply()接受的是一個參數數組。ui

// ··· 同上
    fun1.apply(obk, [1, 2]); // 效果和fun1.call(obj, 1, 2)相同
複製代碼

bind()

bind()建立一個新的函數, 當這個新函數被調用時this鍵值爲其提供的值,其參數列表前幾項值爲建立時指定的參數序列。          ----- MDNthis

bind()的使用方法和call()十分相似,它的第一個參數是須要綁定的this對象,以後的參數爲函數運行所需的參數列表。下面讓咱們來試驗一下。spa

let obj = {
    a: 1
}

function fun1 (num1, num2) {
    console.log(this);
    console.log(num1 + num2);
    console.log(this.a);
}

fun1.bind(obj, 1, 2); // fun1 { ··· }
複製代碼

不一樣於apply()call()bind()返回的並非fun1執行完畢的返回值,而是更改了this並初始化參數以後的fun1的函數定義。所以,要執行fun1,需在bind()後面再加一對括號:code

fun1.bind(obj, 1, 2)(); // 改變this並傳入參數後執行fun1
複製代碼

apply()call()bind()的比較

相同點

  • 都可改變函數this關鍵字的指向。

不一樣點

  • apply()接受一參數數組,返回函數執行的結果。
  • call()接受一組參數,返回函數執行的結果。
  • bind()接受一組參數,返回函數體。需在bind()後加小括號才能執行函數。

箭頭函數的this綁定

ES6中新加入了箭頭函數,它的綁定徹底繼承自調用它的做用域。綁定後不管使用apply()call()仍是bind()都不可修改對象

相關文章
相關標籤/搜索