1. 程式人生 > >學習javascript過程中遇到的that=this的調查解惑

學習javascript過程中遇到的that=this的調查解惑

最近寫微信小程式就在學js,關於關鍵字this的指向不是很理解,於是在收集了一系列資料以後做了以下整理,便於自己加深理解。

首先是這個講解的比較全:JavaScript中的物件查詢 他說這麼說的:

首先,this物件只會在一個函式中需要確定,如果是在全域性域下,this永遠為Global物件,在瀏覽器中通常就是window物件。而在javascript中,函式的呼叫一共有4種方式:

  • Function Invocation Pattern
諸如foo()的呼叫形式被稱為Function Invocation Pattern,是函式最直接的使用形式,注意這裡的foo是作為單獨的變量出現,而不是屬性。
在這種模式下,foo函式體中的this永遠為Global物件,在瀏覽器中就是window物件。
  • Method Invocation Pattern
諸如foo.bar()的呼叫形式被稱為Method Invocation Pattern,注意其特點是被呼叫的函式作為一個物件的屬性出現,必然會有“.”或者“[]”這樣的關鍵符號。
在這種模式下,bar函式體中的this永遠為**“.”或“[”前的那個物件**,如上例中就一定是foo物件。
  • Constructor Pattern
new foo()這種形式的呼叫被稱為Constructor Pattern,其關鍵字new就很能說明問題,非常容易識別。
在這種模式下,foo函式內部的this永遠是new foo()返回的物件。
  • Apply Pattern
foo.call(thisObject)和foo.apply(thisObject)的形式被稱為Apply Pattern,使用了內建的call和apply函式。
在這種模式下,call和apply的第一個引數就是foo函式體內的this,如果thisObject是null或undefined,那麼會變成Global物件。

應用以上4種方式,確定一個函式是使用什麼樣的Pattern進行呼叫的,就能很容易確定this是什麼。

這裡說到了4種呼叫模式,能明確分類的情況下this的指向就一目瞭然,但是你可能會說光看文字還是有點不太理解,那好,下面又有個大神是這麼解釋的:

this 的值到底是什麼?一次說清楚

JS(ES5)裡面有三種函式呼叫形式:
func(p1, p2) 
obj.child.method(p1, p2)
func.call(context, p1, p2) // 先不講 apply
一般,初學者都知道前兩種形式,而且認為前兩種形式「優於」第三種形式。
從看到這篇文章起,你一定要記住,第三種呼叫形式,才是正常呼叫形式:

func.call(context, p1, p2)
其他兩種都是語法糖,可以等價地變為 call 形式:
func(p1, p2) 等價於
func.call(undefined, p1, p2)
obj.child.method(p1, p2) 等價於
obj.child.method.call(obj.child, p1, p2)
請記下來。(我們稱此程式碼為「轉換程式碼」,方便下文引用)
至此我們的函式呼叫只有一種形式:

func.call(context, p1, p2)
這樣,this 就好解釋了
this,就是上面程式碼中的 context。就這麼簡單。
this 是你 call 一個函式時傳的 context,由於你從來不用 call 形式的函式呼叫,所以你一直不知道。
先看 func(p1, p2) 中的 this 如何確定:
當你寫下面程式碼時

function func(){
  console.log(this)
}
func()
等價於
function func(){
  console.log(this)
}
func.call(undefined) // 可以簡寫為 func.call()
按理說打印出來的 this 應該就是 undefined 了吧,但是瀏覽器裡有一條規則:
如果你傳的 context 就 null 或者 undefined,那麼 window 物件就是預設的 context(嚴格模式下預設 context 是 undefined)
因此上面的列印結果是 window。
如果你希望這裡的 this 不是 window,很簡單:

func.call(obj) // 那麼裡面的 this 就是 obj 物件了
再看 obj.child.method(p1, p2) 的 this 如何確定
var obj = {
  foo: function(){
    console.log(this)
  }
}
obj.foo() 
按照「轉換程式碼」,我們將 obj.foo() 轉換為
obj.foo.call(obj)

好了,this 就是 obj。搞定。

以上的文字裡面講到了語法糖和函式轉換,各種模式都可以轉換成Apply Pattern,然後就很簡單的取出第一個引數即可。但是他沒有說到Constructor Pattern的這個模式,但這個好理解:“foo函式內部的this永遠是new foo()返回的物件”,而且有new這個關鍵字在幫你區分。

更多的擴充套件那個大神也說到了:你怎麼還沒搞懂 this?

練習題:Javascript中this關鍵字詳解

說了那麼多,還沒說為什麼要用that=this。這麼搞的目的就是在操作this的內容之前先把當前狀態備份下來。