Day 18:this 關鍵字 (4)
函數執行環境下 (Function Context) (續)
7. 回呼函數 (Callback Function) 裡的 this
this
物件:視乎怎麼呼叫 Callback Function。
JavaScript 裡常會需要用到 Callback Function,將某個函數物件 A 當作參數傳進另一個函數 B,由函數 B 決定執行 A 的時機。
這時候就要注意函數 B 是如何去呼叫函數 A,否則函數 A —— 也就是 Callback Function —— 裡面的 this
,很可能不是你所預期的對象。
7.1. 簡單呼叫 Callback Function (一般模式)
今天我有一個 hero
物件,存在一些屬性,例如 name
,我想透過 Callback 的方式去控制 hero
物件,我只在 hero
物件裡實作一個 act()
,負責執行 Callback Function。而 Callback Function 的內容由其他人提供。例如以下:
hero.act(sayHi)
就是一個 callback 的用法,sayHi
就是 callback function。在
hero.act()
裡,採用簡單呼叫的方式來執行 callback function。根據昨天介紹的「 2.簡易呼叫 (Simple Call) 」,函數裡的
this
會是 Global 物件,所以hero.act(sayHi)
回傳的結果是 Global 變數的name
。
7.2. 簡單呼叫 Callback Function (嚴謹模式)
如果在嚴謹模式下,透過簡單呼叫,函數裡
this
會是undefined
,無法執行this.name
,會發生錯誤。
但上述的範例,我想達到的效果是 hero.act(sayHi)
可以回傳物件 hero
自己的 name
值,我該怎麼做?
7.3. 用 apply() / call() 將物件本身傳入 Callback Function
如果想把物件本身帶入 Callback Function 裡的 this
,就要用 apply()
/ call()
。
總結 this
要判斷 this 是誰,就看是誰呼叫
this
出現的位置有可能在:
全域執行環境下 (Global Context)
函數執行環境下 (Function Context)
但全域執行環境下 (Global Context) 遇到的機率相對低,而且十分單純,this
就是 Global 物件本身。
比較容易發生問題的是函數執行環境 (Function Context),遇到的情境可能千變萬化,過程可能讓人很混淆。
記得一個大原則:看呼叫時的物件是誰。
JavaScript 的 this
不是看定義的語彙位置,而是根據執行當下誰擁有這段程式碼,也就是看誰呼叫的。
但要注意的是,簡單呼叫 (Simple Call) 的情形下,一般模式和嚴謹模式會有不同的行為。
函數執行環境下,判斷 this 的公式秘笈
所有人都知道,寫程式就像學數學一樣,不建議背誦,而是去理解背後原理 (話說回來,比樂透可能性還多的語法組合,企圖用背的也很不科學)。
但當你確定你已經理解原理之後,我不反對用一些類似口訣或公式筆記的方式來輔助記憶,幫助快速回憶。畢竟如果每次寫程式要用到時,都從頭推導,那效率是不現實的。
曾有人做過實驗,讓大學數學教授和高中生一起做同一份高中數學考券,結果高中生輕輕鬆鬆在時間內完成,數學教授卻沒有寫完。是因為數學教授的程度比高中生差嗎?
當然不是。
數學教授每一個題目都知道背後原理,給他足夠的時間推導,他每一題都能完美解答。但考試時間是有限的,對那些高中生來說,這些題目範圍是他們非常熟悉,幾乎看到題目腦海就浮現解法。這代表那些高中生不理解背後原理嗎?不,他們也是經過理解的過程學到這些題目的解法,但為了應付嚴峻的考試,他們用各種方法來加速遇到題目的解決速度,例如解題口訣、公式表。
現實中的專案開發也有同樣情境。專案開發通常有時程限制,為了減少每次回憶的時間,相信很多工程師都有自己的私藏筆記,這些筆記就是你理解的精華,用來幫助自己快速回想,或減少從頭推導的時間。
前面舉了非常多情境,整體歸納下來,大致上不出以下公式的範圍:
以上指的都是未經
bind()
綁定而來的函數物件透過
bind()
產生的函數,不管呼叫方式為何,this
都指向當初bind()
所綁定的物件。
小補充:this
不是變數
this
不是變數這一點我想大家都清楚,只是作為 this
介紹完整性的一個小補充。
正如最一開始所說,this
是一個關鍵字,不是變數,所以不能改變 this 的值,例如企圖這樣:
References
Last updated