說優化之前,先講點題外話
首先利用遞歸計算數的階乘,話不多說上代碼:
var count = 0;
function factorial(num){
count++; //此處利用count計算此函數被調用的次數
if( num == 0 || num == 1){
return 1;
}
return num * factorial(num-1);
}
//然後,求一到五的階乘
for(var i = 1; i<=5;i++){
console.log(factorial(i));
}
//然後再輸出count,即函數被調用的次數
console.log(count); // 15
可以看到,該函數被調用了15次,代價十分昂貴。
如果算5!時,能把4!保存出來,那算4!時就不用重新計算了!
那麼改造一下上述代碼:
var count = 0;
var cache = [];//建立一個空數組,用作緩存
function factorialA(num){
count++; //此處利用count計算此函數被調用的次數
if(cache[n]){
return cache[n];
}else{
if( num == 0 || num == 1){
cache[0] = 1;
cache[1] = 1;
return 1;
}else{
cache[n] = num * factorial(num-1);
return cache[n];
}
}
}
//然後,求一到五的階乘
for(var i = 1; i<=5;i++){
console.log(factorial(i));
}
//然後再輸出count,即函數被調用的次數
console.log(count); // 9
顯而易見,執行次數明顯降低,相對應執行的時間也是大大降低。
但是上面的寫法顯然是不樂意的,我們不能再全局變量裏創建一個這樣的變量,並且要符合私有的特性,不能讓其他對象能夠改變他!
所以要把原有函數封裝成一個具有函數記憶功能的函數。
說到這裏應該會想到一個名詞:閉包
沒錯,此處就利用閉包實現這樣的功能。
function memorize(fn){
var cache = {};//因爲對象的查找速度是比數組要快的
return function(){
var key = arguments.length + Array.prototype.join.call(arguments);//使key唯一併且是字符串
if(cache[key]){
return cache[key];
}else{
cache[key] = fn.apply(this,arguments);//此處使用apply 參數是this,所以並沒有改變this的指向,目的是爲了把arguments傳進去,因爲apply的第二個參數可以傳數組
return cache[key];
}
}
}
var newF = memorize(factorial);
總結:應用場景:需要之前運算結果的情況下,但需要在內存和執行時間上做取捨。