Day 17:this 關鍵字 (3)
函數執行環境下 (Function Context) (續)
5. 顯性函數綁定之 call()/apply() 篇 (Explicit Function Binding for call()/apply())
this
物件:函數物件被執行時所指定的綁定物件,也就是Function.prototype.call()
或Function.prototype.apply()
的第一個參數。
由於 apply()
和 call()
幾乎一樣,差別只在於參數的形式不同:
call()
接受一連串獨立的參數。apply()
接受一組陣列形式的參數。
因此以下範例只用 apply()
來示範。
5.1. 和 bind() 的差別
apply()
/ call()
和上一節介紹的 bind()
非常相似,都是對函數物件做綁定物件的指定,使用的語法形式也很像。
但同樣對某個函數物件 A 使用時, bind()
和 apply()
/ call()
的差別在於:
bind()
會建立一個新的函數物件 B,為 B 綁定一個特定物件,然後回傳 B 物件本身。B 會繼承了 A 的原型。如果 A 已經有用
bind()
綁定過,B 也會繼承相同的綁定物件,無法再綁新的 (前面 4.3 的範例)。
apply()
/call()
會執行函數物件 A,指派一個物件作為this
,然後回傳函數 A 的執行結果。如果 A 已經有用
bind()
綁定過,用apply()
/call()
再指派其他的物件也沒用。
5.2. 綁定物件範例 (一般模式 & 嚴謹模式)
由於一般模式和嚴謹模式的行為一樣,這裡以一般模式示範。
直接以要執行的函數物件本身 (e.g., whatsThis
, getFullName
) 去呼叫 apply()
,第一個參數就是函數裡的 this
。
透過這種方式指定函數的綁定物件,也不需要另外建立一個新的函數物件,即插即用。在使用靈活性上,我認為比 bind()
方便。
5.3. 對已經被 Binding 過的函數物件無效
上一節提過,bind()
就像海誓山盟,一個函數物件只要曾經和某個物件進行綁定就會死心踏地,即使再進行二次 bind()
或利用 apply()
指派一次性的綁定物件,都不會生效。
以下對每個函數物件的綁定狀況逐一解說:
getFullName()
這個函數物件本身沒有綁定過任何物件。introIronMan()
是透過getFullName()
產生的新函數物件,綁定了ironMan
。introClone()
是透過introIronMan()
產生的新函數物件,雖然語法沒有指定新的綁定物件,但透過繼承,同樣綁定了ironMan
。introSpiderMan()
是透過introIronMan()
產生的新函數物件,雖然語法指定了新的綁定物件spiderMan
,但由於繼承了introIronMan()
的綁定關係,因此綁定物件同樣是ironMan
。introClone()
和introSpiderMan()
因為本身函數物件已經存在綁定了ironMan
的關係,即使透過apply()
指派新的物件,執行時函數內的this
永遠仍是ironMan
。getFullName()
因為沒有存在任何綁定關係,因此透過apply()
,可以成功將函數內的this
指派為spiderMan
。
6. this
指向 new
所產生的新物件
this
指向 new
所產生的新物件
this
物件:new
所產生的新物件。
當對函數使用 new
關鍵字來產生一個物件,該物件會形成自己的環境 (Context),例如以下範例:
原本函數內的
this.exp
變成新物件h
的屬性。一般模式和嚴謹模式是一樣的行為。
References
Last updated