不知道的js——性能優化之函數記憶

說優化之前,先講點題外話

首先利用遞歸計算數的階乘,話不多說上代碼:

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);

總結:應用場景:需要之前運算結果的情況下,但需要在內存和執行時間上做取捨。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章