JavaScript:this指標
this指標,儲存的是一個記憶體地址,如同變數一樣,指向一塊記憶體區域;
而這個記憶體區域,儲存的就是一個物件的資料,那麼這個物件是什麼呢?
通常來說,this指標,主要是用在方法(函式)中,用來指向呼叫方法(函式)的物件;
比如說,有個方法eat()
,這個方法裡面有個this指標;
當Tom
呼叫eat
時,this指標指向的就是"Tom";
當Jerry
呼叫eat
時,this指標指向的就是"Jerry";
也就是說,this指標,總是指向直接呼叫者。
好,現在我們來看一下,兩個不同於上面所述規則的特殊情況:
-
”沒有“呼叫者
看下面程式碼:
我們知道,如果是使用
var
宣告的變數,實際上是成為了window
aaa()
實際上就是window.aaa()
,也就是省略了window
的寫法,那麼,this指向的就是window
物件,我們可以理解;但是,上面我們使用
let
宣告的變數,為什麼this指向的還是window
物件呢?要知道,
let
宣告的函式,並不是window
物件的方法,window
物件也無法呼叫,那麼此時aaa()
是由誰呼叫的呢?我們現在無法得知,但是可以肯定的是,絕對不是window
物件;再來看函式
aab()
,雖然它是function
宣告的函式,但是因為它是在程式碼塊中宣告的,所以它也不是window
物件的方法,那麼aab()
又是被誰呼叫的呢?為什麼它的this指標,也指向window
事實上,這是歷史遺留問題,如果我們開啟了嚴格模式,此時兩個this將都會是
undefined
,這是符合邏輯的,既然“沒有”呼叫者,那麼this就沒有指向,當然就是undefined
;如下所示,就印證了我們前面所說的:
-
箭頭函式沒有this指標
首先說明,箭頭函式,確實沒有自己的this指標;
也就是說,箭頭函式裡面的this,並不能指向呼叫箭頭函式的物件;
那麼,此時this,指向的是誰呢?
看下面程式碼:
我們將上圖與上上圖進行比較,仔細觀察一下輸出結果的不同;
在嚴格模式下,上圖三個this指向的都是
window
物件,與上上圖完全不一樣,這至少說明,箭頭函式的this,和function
再看下面這個程式碼:
上圖與上上圖的區別,就是在最後一行程式碼,我們將obj1作為obj2的一個物件,從而再多一次呼叫
arrow()
方法,結果依然還是指向window
物件,似乎無論增加多少次中間呼叫者,最終都會指向window
物件,說明箭頭函式的this,並不是在指向呼叫箭頭函式的物件;現在我們嘗試,將箭頭函式
arrow
的可見性,降低一些,看下面的程式碼:上圖將箭頭函式
內arrow
的可見性,控制在了用關鍵字function
宣告的函式外arrow
內部,這樣,要使用箭頭函式,就得呼叫外arrow
;對於
arrow()
,上面我們已經討論過,此時外arrow
函式“沒有”呼叫者,所以this是undefined
;對於
obj1.arrow()
,此時this指向,呼叫外arrow
函式的obj1;對於
obj2.arrow()
,此時this指向,呼叫外arrow
函式的obj2;對於
obj2.obj1.arrow()
,此時this指向,呼叫外arrow
函式的obj1,注意,此時obj2呼叫obj1,而obj1呼叫外arrow
函式,所以this指向obj1;可以看到,this的表現,完全就是
外arrow
函式的this指標的表現;也就是說,此時,箭頭函式的this,其實並不屬於箭頭函式,而是屬於包圍箭頭函式的外部程式碼塊,在這裡也就是指
外arrow
函式;所以,在考慮箭頭函式的this指標的指向的時候,我們完全可以把箭頭函式當成一般的執行語句,而不是一個函式,這也是為什麼說箭頭函式沒有this指標的緣故;
現在回過頭看上上圖,我們就能理解,此時箭頭函式是直接在script標籤中的,作為一個普通的執行語句,它的外層只剩下瀏覽器視窗,也就是
window
物件了,所以這些this指標才全部指向window
物件;
總結:
- this指標,總是指向它所在函式體的直接呼叫者;
- 直接
函式名()
這樣“沒有”呼叫者的函式呼叫,在嚴格模式下,this為undefined;在普通模式下,this指向window
物件; - 箭頭函式沒有this指標,此時將箭頭函式當做一般語句,this指標屬於箭頭函式所在的函式體的直接呼叫者;而且注意,如果箭頭函式是全域性作用域的話,無論什麼模式,this總是指向
window
物件;