[教學] 3個JavaScript的call()和apply()的應用範例
這篇教學會用3個JavaScript中運用到apply()
和call()
的例子,讓你快速了解apply()
和call()
的使用方法。
目錄
範例應用1: Call Forwarding
有時候,我們想要在一個函式原本的功能之上附加額外的功能,這個時候可以使用Call Forwarding的技巧。
Call Forwarding用一句話來說就是:用一個wrapper函式把原本的函式包起來,並呼叫原本的函式。
const wrappedFunction = function wrapper() {
return anotherFunction.apply(this, arguments)
}
這裡就會需要用到Function.prototype.apply
,用wrapper
函式的this
和arguments
去呼叫原本的anotherFunction
。
基本的使用方法如下:
function wrapper(func) {
const wrappedFunction = function() {
const result = func.apply(this, arguments) // (*)
// Some custom logic...
return result
}
return wrappedFunction
}
const wrappedFoo = wrapper(foo)
wrappedFoo(bar, baz)
wrapper
函式的引數是一個函式func
,回傳值是另一個函式 wrappedFunction
。
當wrappedFunction
被呼叫的時候,會執行原本的func
,並且加上你想要的邏輯,最後回傳func
被執行的結果。
核心在執行func
的這一行(*)
,也就是func.apply(this, arguments)
。
補充說明:arguments
arguments
是一個函式內部特別的變數,對應到函式被呼叫時傳進來的引數。
我們需要用到wrappedFunction
的arguments
變數,因為我們會用和func
一樣的參數呼叫wrappedFunction
,但是我們事先不知道func
會有幾個參數。
補充說明:apply()
apply()
是函式物件的一個方法,用法是
someFunction.apply(context, arguments)
以下兩者效果大概相同,除了用Function.prototype.apply
呼叫someFunction
時,this
的值會是context
。:
someFunction(1, 2, 3)
someFunction.apply(context, [1, 2, 3])
因此呼叫func
時的this
等於wrappedFunction
被呼叫時的this
。
我們需要特別注意呼叫時的this
,是因為也會有以下的使用情境:
const worker = {
someMethod() {
return 1;
},
slow(x) {
return x * this.someMethod()
}
}
worker.slow = wrapper(worker.slow)
worker.slow()
如此一來wrappedFunction
呼叫起來跟原本的函式幾乎一模一樣,但是又加上了自己想要的邏輯。
範例應用2: Cache
假設有個計算量非常費時的函式:
function slow(x) {
// Some CPU heavy task
return x
}
我們希望加上cache的功能,如果用相同的參數去呼叫這個函式第二次的話,就直接回傳上一次計算過的結果:
function cachingDecorator(func) {
let cache = new Map() // The cache
return function() {
const key = hash(arguments) // Some hash function
if (cache.has(key)) {
return cache.get(key) // Retrieve value from the cache
}
const result = func.apply(this, arguments) // Compute result
cache.set(key, result) // Save value to the cache
return result
}
}
slow = cachingDecorator(slow)
slow(1)
slow(1) // Cached!
slow(1) // Cached!
範例應用3: Method Borrowing
上例中的hash()
的實作需要注意。
以下寫法有問題,因為arguments
不是一個array,沒有join
方法:
function hash() {
return arguments.join(',') // Not working!
}
但是利用Function.prototype.call
,就可以借用Array.prototype.join
方法:
function hash() {
return [].join.call(arguments, ',')
}