使用闭包实现的缓存功能

    jwolf 
4141  0  0   2016-8-23 7:44


       JavaScript的闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。变量的作用域仅限于包含它们的函数,因此无法从其它程序代码部分进行访问。不过,变量的生存期是可以很长,在一次函数调用期间所创建所生成的值在下次函数调用时仍然存在。正因为这一特点,闭包可以用来完成信息隐藏,并进而应用于需要状态表达的某些编程范型中。

   也正是这一特点,保留在内存中的变量能被快速读取,这跟缓存的概念就挂上钩了,上代码:

function memorize(f){
  var cache = {};
  return function(){
    var key = arguments.length + Array.prototype.join.call(arguments,',');
    if(key in cache){
      return cache[key];
    }else{
      return cache[key] = f.apply(this,arguments);
    }
  }
}

   外部函数中有cache变量,在return的函数里面有对cache的引用,由于闭包的特点,cache变量保持了其持久性。返回的函数中存在一个key变量,key是由参数的长度和参数组成的字符串组合成的,保证了参数的唯一性。我们先创建一个示范的函数,计算最大公约数:

function gcd(a,b){
  var t;
  if(a<b) t=b,b=a,a=t;
  while(b!=0){
    t=b,b=a%b,a=t;
    return a;
  }
}

完整的代码如下:

function memorize(f){
  var cache = {};
  return function(){
    var key = arguments.length + Array.prototype.join.call(arguments,',');
    if(key in cache){
      return cache[key];
    }else{
      return cache[key] = f.apply(this,arguments);
    }
  }
}

function gcd(a,b){
  var t;
  if(a<b) t=b,b=a,a=t;
  while(b!=0){
    t=b,b=a%b,a=t;
    return a;
  }
}
var gcdmemo = memorize(gcd);
gcdmemo(85,187);
gcdmemo(85,187);

  第一次调用gcdmemo的时候,我们的程序计算出结果的同时,把参数的唯一标识和结果以key-value的方式保存到闭包中的变量cache中,于是第二次调用的时候,我们的' key in cache '是返回true的,达到了直接从内存中读取的目的。如果说这个例子意义不大,那我们看一个递归相关的:

var f = memorize(function(n){
   return (n<=1)?1:n*f(n-1);
});
f(5);

   上面的程序,当结果计算出来之后,4~1的值也存在我们的cache中,再次调用的时候我们就直接返回了记忆的值,达到使用内存空间来提高计算效率的效果。当然,这需要适合的场景才能使用,毕竟cache是占用着内存的。