Function.prototype.call() and Function.prototype.apply()
JavaScript 調用 function object 的方式,除了傳統的 () 算符
[若用 C++ 的表達方式,即 operator()
],還可以藉由 call()
和 apply()
兩種個體行為調用。
call()
和 apply()
的差別主要在於 call()
只接受一個參數,即 call(thisArg)
;而 apply()
接受兩個參數,即 apply(thisArg, argArray)
。透過 call()
和 apply()
調用函數的主要目的,在於改變函數內部的 this
名稱所指涉的對象。對一般函數而言,當 programmer 在函數內部使用 this
名稱時,指涉對象是 global object
。global object
是運行環境中最頂層的個體,在瀏覽器環境中,global object
就是 window
此一個體。但是 call()
和 apply()
可以改變 this
名稱所指涉的對象。
If thisArg is null or undefined, the called function is passed the global object as the this value. Otherwise, the called function is passed ToObject(thisArg) as the this value. ECMAScript Language Specification - Standard ECMA-262 3rd Edition. 15.3.4.3 & 15.3.4.4
首先,先來一段測試程式實證上面的標準規範內容。
結果證實規範內容所言無誤。因此,我們可以利用 call()
和 apply()
改變函數內部的 this
名稱所指涉的對象。此一技巧最常運用在事件處理函數中,例如《Rendering images with title and box》就是這種技巧的實踐。在該例中,使用 call()
調用 renderImage() ,而將圖像索引值設定為屬性 myIndex 。其實像這種需要傳遞參數的情形,可以改用 apply()
,將要傳遞給 function object 的參數按順序放置在 apply() 行為的第二個 argArray
參數中。因此《Rendering images with title and box》用 apply()
改寫如下所示。
由於 apply()
的第二個 argArray
參數必須是陣列形式,所以要將 i 放入陣列中。其次, apply()
是按照變數在 argArray
陣列中的順序代換參數列的變數,故參數列的第一個參數內容,等於 argArray
中的第 0 個元素,以下類推。因此在上例中 renderImage(index) 中的 index 等於 argArray
中的第 0 個元素 (即 i) 。
樂多舊回應