[教學] 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, ',')
}