乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      JavaScript Memoization:讓函數(shù)也有記憶功能

       chanvy 2008-11-20
      Author: YY in Limbo 混沌??裣?/div>

      realazy在blog上給出了一個(gè)JavaScript Memoization的實(shí)現(xiàn),Memoization就是函數(shù)返回值的緩存,比如一個(gè)函數(shù)參數(shù)與返回結(jié)果一一對(duì)應(yīng)的hash列表,wiki上其實(shí)也有詳細(xì)解釋,我不細(xì)說(shuō)了,只討論一下具體實(shí)現(xiàn)的問(wèn)題,realazy文中的代碼有一些問(wèn)題,比如直接用參數(shù)拼接成的字符串作為查詢(xún)緩存結(jié)果的key,如果參數(shù)里包括對(duì)象或數(shù)組的話(huà),就很難保證唯一的key,還有1樓評(píng)論里提到的:[221,3]和[22,13]這樣的參數(shù)也無(wú)法區(qū)分。

      那么來(lái)改寫(xiě)一下,首先還是用hash表來(lái)存放緩存數(shù)據(jù):


      1. function Memoize(fn){
      2.     var cache = {};
      3.     return function(){
      4.         var key = [];
      5.         for( var i=0, l = arguments.length; i < l; i++ ) 
      6.             key.push(arguments[i]);
      7.         if( !(key in cache) )
      8.             cache[key] = fn.apply(this, arguments);
      9.         return cache[key];
      10.     };
      11. }

      嗯,區(qū)別是直接把數(shù)組當(dāng)作鍵來(lái)用,不過(guò)要注意函數(shù)里的arguments是js解釋器實(shí)現(xiàn)的一個(gè)特殊對(duì)象,并不是真正的數(shù)組,所以要轉(zhuǎn)換一下……

      ps: 原來(lái)的參數(shù)包括方法名稱(chēng)和上下文引用:fib.fib_memo = Memoize(’fib_memo’, fib),但實(shí)際上currying生成的函數(shù)里可以用this直接引用上層對(duì)象,更復(fù)雜的例子可以參考John Resig的makeClass,所以我改成直接傳函數(shù)引用:fib.fib_memo = Memoize(fib.fib_memo)

      這樣寫(xiě)看上去似乎很靠譜,由參數(shù)組成的數(shù)組不是唯一的么。但實(shí)際上,數(shù)組之所以能作為js對(duì)象的屬性名稱(chēng)來(lái)使用,是因?yàn)樗划?dāng)作字符串處理了,也就是說(shuō)如果你給函數(shù)傳的參數(shù)是這樣:(1,2,3), cache對(duì)象就會(huì)是這個(gè)樣子:{ “1,2,3″: somedata },如果你的參數(shù)里有對(duì)象,比如:(1,2,{i:”yy”}),實(shí)際的鍵值會(huì)是:”1,2,[object Object]”,所以這跟把數(shù)組拼接成字符串的方法其實(shí)沒(méi)有區(qū)別……

      示例:

      1. var a = [1,2,{yy:'0'}];
      2. var b = [1,2,{xx:'1'}];
      3. var obj = {};
      4. obj[a] = "111";
      5. obj[b] = "222";
      6. for( var i in obj )
      7.     alert( i + " = " + obj[i] );    //只會(huì)彈出"1,2,[object Object] = 222",obj[a] = "111"被覆蓋了

      直接用參數(shù)作為鍵名的方法不靠譜了…………換一種方法試試:

      1. function Memoize(fn){
      2.     var cache = {}, args = [];
      3.     return function(){
      4.         for( var i=0, key = args.length; i < key; i++ ) {
      5.             if( equal( args[i], arguments )  )
      6.                 return cache[i];
      7.         }
      8.         args[key] = arguments;
      9.         cache[key] = fn.apply(this, arguments);
      10.         return cache[key];
      11.     };
      12. }

      可以完全避免上述問(wèn)題,沒(méi)有使用hash的鍵值對(duì)索引,而是把函數(shù)的參數(shù)和結(jié)果分別緩存在兩個(gè)列表里,每次都先遍歷整個(gè)參數(shù)列表作比較,找出對(duì)應(yīng)的鍵名/ID號(hào)之后再?gòu)慕Y(jié)果列表里取數(shù)據(jù)。以下是比較數(shù)組的equal方法:

      1. function equal( first, second ){
      2.     if( !first || !second || first.constructor != second.constructor )
      3.         return false;
      4.     if( first.length && typeof first != "string"  )
      5.         for(var i=0, l = ( first.length > second.length ) ? first.length : second.length; i<l; i++){
      6.             if( !equal( first[i], second[i] ) ) return false;
      7.         }
      8.     else if( typeof first == 'object' )
      9.         for(var n in first){
      10.             if( !equal( first[n], second[n] ) ) return false;
      11.         }
      12.     else
      13.         return ( first === second );
      14.     return true;
      15. }

      千萬(wàn)不要直接用==來(lái)比較arguments和args里的數(shù)組,那樣比較的是內(nèi)存引用,而不是參數(shù)的內(nèi)容。

      這種方法的速度很慢,equal方法其實(shí)影響不大,但是緩存的結(jié)果數(shù)量多了以后,每次都要遍歷參數(shù)列表卻是很沒(méi)效率的(求80以上的fibonacci數(shù)列,在firefox3和safari3上都要40ms左右)

      如果在實(shí)際應(yīng)用中參數(shù)變動(dòng)不多或者不接受參數(shù)的話(huà),可以參考Oliver Steel的這篇《One-Line JavaScript Memoization》,用很短的函數(shù)式風(fēng)格解決問(wèn)題:

      1. function Memoize(o, p) {
      2.     var f = o[p], mf, value;
      3.     var s = function(v) {return o[p]=v||mf};
      4.     ((mf = function() {
      5.         (s(function(){return value})).reset = mf.reset;
      6.         return value = f.apply(this,arguments); //此處修改過(guò),允許接受參數(shù)
      7.     }).reset = s)();
      8. }

      示例:

      1. var fib = {
      2.     temp: function(n){
      3.         for(var i=0;i<10000;i++)
      4.             n=n+2;
      5.         return n;
      6.     }
      7. }
      8.  
      9. Memoize(fib,"temp"); //讓fib.temp緩存返回值
      10.  
      11. fib.temp(16); //執(zhí)行結(jié)果:20006,被緩存
      12. fib.temp(20); //執(zhí)行結(jié)果:20006
      13. fib.temp(10); //執(zhí)行結(jié)果:20006
      14.  
      15. fib.temp.reset(); //重置緩存
      16. fib.temp(10); //執(zhí)行結(jié)果:20010

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶(hù) 評(píng)論公約

        類(lèi)似文章 更多