JavaScript中this的解析

前言

  • this既不指向自身,也不指向函數的詞法作用域。
  • this的綁定不是在編寫代碼的時候綁定的,而是在它運行的時候進行的。
  • this的綁定和函數的聲明位置沒有任何關係,只取決於函數的調用方式。

this的綁定規則

this有四種綁定規則:

  • 默認綁定
  • 隱式綁定
  • 顯示綁定
  • new綁定

讓我們先來解釋一下這四個規則。

默認綁定

函數的獨立調用是函數最常見的一種調用方式,即直接使用不帶任何修飾的函數引用進行的調用,此時函數中的this會默認綁定到全局對象。(在非嚴格模式下,嚴格模式會綁定到undefined)。這就是默認綁定。

請看以下代碼:

function foo () {
  console.log(this.a);
}

var a = 2;

foo();//2

此時的foo()直接使用的是不加任何修飾的函數引用的調用,因此函數中的this默認綁定到全局對象。

如果是嚴格模式,就會報錯。

function foo() {

  "use strict"

  console.log(this.a);

}

var a = 2;

foo();  //  TypeError:this is undefined

隱式綁定

當函數的調用存在某個上下文對象時,函數中的this就會綁定在這個上下文對象上。即函數被某個對象當做引用屬性被添加到對象中時。

請看下面的代碼:

function foo () {
  console.log(this.a);
}

var obj = {
  a:2,
  foo:foo,
}

obj.foo();  // 2

foo()的調用不在是獨立函數調用的方式,它的前面加上了對象obj的引用,此時函數內的this就會綁定在這個對象上,this.a和obj.a是一樣的。

注意

在函數調用的時候,前面如果出現對象引用鏈,函數中的this只會綁定到引用鏈的最後一個對象上。

代碼示例:

function foo () {

  console.log(this.a);

}

var obj1 = {
  a:42,
  foo:foo,
}

var obj2 = {
  a:2,
  obj1:obj1,
}

obj2.obj1.foo();  // 42

顯示綁定

顯示綁定並不像隱式綁定那樣,必須在對象內部包含一個指向函數的引用屬性,並通過這個屬性間接的引用函數。顯示綁定則不需要在對象內部包含函數引用,也能強制的調用函數。

JavaScript中可以使用函數的兩個方法來實現這個——apply( )call( )

這兩個方法是如何工作的呢?它們的第一個參數是一個對象,這個對象是給this準備的,接着在調用函數的時候,將this綁定到這個對象上,因爲你可以指定要綁定的對象,所有該綁定稱爲顯示綁定。

代碼演示:

function foo () {

  console.log(this.a);
}

var obj = {
  a:2,
};

foo.apply( obj );  // 2
foo.call( obj );   // 2

這兩個方法在this的綁定上是一樣的,它們的區別是在其他的參數上,(當然我們不在這裏討論它倆的區別),foo()通過這兩個方法可以將this綁定在所傳入的對象上。

new綁定

在使用new來調用函數或者是構造函數的調用時,會發生以下四個步驟:

  1. 創建一個新對象
  2. 這個新對象會被執行[[Prototype]]鏈接
  3. 這個新對象會綁定函數的this。
  4. 如果函數沒有返回其他的對象,那麼new表達式中的函數調用就返回這個新對象。

在這裏我們關心的是第1,3,4步,至於第2步,暫時先跳過。

考慮下面的代碼:

function foo (a) {
  this.a = a;
}

var bar = new foo(2);

console.log(bar.a); // 2

使用new 來調用foo(…)時,會構建一個新的對象,並將this綁定到這個新對象上,最後返回這個新對象。new是最後一種可以影響this綁定行爲的方法,稱之爲new綁定。

綁定規則的優先級

現在我們已經瞭解了這四種綁定規則,但當一個函數運用多種綁定規則時該怎麼辦呢?因此我們現在來測試綁定規則的優先級的問題。

這就是綁定規則的優先級問題,而綁定規則的有限次序是:

new綁定 > 顯示綁定 > 隱式綁定 > 默認綁定

總結

現在我們可以通過綁定規則的優先級來進行判斷this的綁定對象:

  1. 函數如果是在new中調用,那麼this就會綁定在新創建的對象的上。

    var bar = new foo()

  2. 函數是否apply,call來調用,如果是的話,this就綁定到那個指定的對象上。

    var bar = foo.apply(obj)

  3. 函數是否在某個上下午中調用,如果是的話,this就綁定到那個上下文對象上。

    var bar = obj.foo()

  4. 如果以上都不是的話,那就是默認綁定,如果在嚴格模式下,this綁定的是undefined,如果是非嚴格模式下,this綁定的是全局對象。

    var bar = foo()

this的綁定就是這樣了。

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