淺談自記憶函數 最近閱讀《JavaScript忍者秘籍》看到了一種有趣的函數:自記憶函數。 簡介 何為自記憶函數?書中提到: 記憶化(memoization)是一種構建函數的處理過程,能夠記住上次計算結果 通過這句話可以得出,自記憶函數其實就是能夠記住上次計算結果的函數。在實現中,我們可以這樣進行處 ...
淺談自記憶函數
最近閱讀《JavaScript忍者秘籍》看到了一種有趣的函數:自記憶函數。
簡介
何為自記憶函數?書中提到:
記憶化(memoization)是一種構建函數的處理過程,能夠記住上次計算結果
通過這句話可以得出,自記憶函數其實就是能夠記住上次計算結果的函數。在實現中,我們可以這樣進行處理:當函數計算得到結果時,就將該結果按照參數存儲起來。採取這種方式時,如果另外一個調用也使用相同的參數,我們則可以直接返回上次存儲的結果而不是再計算一遍。
顯而易見,像這樣避免既重覆又複雜的計算可以顯著提高性能。對於動畫中的計算、搜索不經常變化的數據或任何耗時的數學計算來說,記憶化這種方式是十分有用的。
一個自記憶函數的例子
下麵這個例子展現自記憶函數的工作方式:
// 自記憶素數檢測函數
function isPrime (value) {
// 創建緩存
if (!isPrime.answers) {
isPrime.answers = {};
}
// 檢查緩存的值
if (isPrime.answers[value] !== undefined) {
return isPrime.answers[value];
}
// 0和1不是素數
var prime = value !== 0 && value !== 1;
// 檢查是否為素數
for (var i = 2; i < value; i++) {
if (value % i === 0) {
prime = false;
break;
}
}
// 存儲計算值
return isPrime.answers[value] = prime
}
isPrime
函數是一個自記憶素數檢測函數,每當它被調用時:
首先,檢查它的answers
屬性來確認是否已經有自記憶的緩存,如果沒有,創建一個。
接下來,檢查參數之前是否已經被緩存過,如果在緩存中找到該值,直接返回緩存的結果。
如果參數是一個全新的值,進行正常的素數檢測。
最後,存儲並返回計算值。
總結
自記憶函數有兩個優點:
- 由於函數調用時會尋找之前調用所得到的值,所以用戶最終會樂於看到所獲得的性能收益。
- 它不需要執行任何特殊請求,也不需要做任何額外初始化,就能順利進行工作。
但是,自記憶函數並不是完美的,它一樣有著缺陷:
- 任何類型的緩存都必然會為性能犧牲記憶體。
- 很多人認為緩存邏輯不應該和業務邏輯混合,函數或方法只需要把一件事情做好。
- 對自記憶函數很難做負載測試或估算演算法複雜度,因為結果依賴於函數之前的輸入。