当前位置: 首页 > 图文教程 > 网络编程 > Javascript > JavaScript工厂模式的memoizing技术

Javascript
jQuery中isFunction方法的BUG修复
将函数的实际参数转换成数组的方法
javascript 删除数组中重复项(uniq)
js 巧妙去除数组中的重复项
javascript下一种表单元素获取方法存在的问题
javascript 三种数组复制方法的性能对比
js 多层叠的TAB选项卡
javascript 自动标记来自搜索结果页的关键字
起点页面传值js,有空研究学习下
javascript 的Document属性和方法集合
JavaScript 使用简略语法创建对象的代码
使用JQuery进行跨域请求
jquery 经典动画菜单效果代码
jquery 常用操作方法
js提示信息jtip封装代码,可以是图片或文章
javascript面向对象的方式实现的弹出层效果代码
jquery中的sortable排序之后的保存状态的解决方法
js或css实现滚动广告的几种方案
使用JavaScript库还是自己写代码?
js 右键菜单,支持不同对象不同菜单(兼容IE、Firefox)

Javascript 中的 JavaScript工厂模式的memoizing技术


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 135 ::
收藏到网摘: n/a

最近在读《JavaScript 设计模式》一书,其中工厂模式中提到了memoizing技术,今天仔细整理了一下memoization 相关的资料,与大家共享。

memoization 一词是Donald Michie 根据拉丁语memorandum杜撰的一个词。相应的动词、过去分词、ing形式有memoiz、memoized、memoizing.

Memoization 是一种将函数返回值缓存起来的方法,Memoization 原理非常简单,就是把函数的每次执行结果都放入一个键值对(数组也可以,视情况而定)中,在接下来的执行中,在键值对中查找是否已经有相应执行过的值,如果有,直接返回该值,没有才 真正执行函数体的求值部分。很明显,找值,尤其是在键值对中找值,比执行函数快多了。现代 JavaScript 的开发也已经大量使用这种技术。

  •  一个简单的使用memoization的例子

我们知道,在不同的浏览器中,xmlHttpRequest对象的具体实现都不同。需要判断何种浏览器以执行具体的方法。这里就有一个使用memoization来实现的例子。

  1. function createXHRObject = function(){
  2.     //先把三个匿名函数缓存起来。
  3.     var methods = [
  4.         function(){return new XMLHttpRequest();},
  5.         function(){return new ActiveXObject("Msxml2.XMLHTTP");},
  6.         function(){return new ActiveXObject("Microsoft.XMLHTTP");}
  7.     ];
  8.     for(var i=0,len=methods.length;i<len;i++){
  9.         try{//这里用try catch来代替了条件判断,通常我不赞成这种写法
  10.             methods[i]();
  11.         }
  12.         catch(e){
  13.             continue;//如果报异常,则执行下一次循环
  14.         }
  15.         // 把createXHRObject 与能正常执行的匿名函数对应起来,再调用createXHRObject不用再检测浏览器了
  16.         createXHRObject = method[i];
  17.         return method[i];
  18.     }
  19. }

以上是一个简单的例子,第一次执行createXHRObject()的时候,会循环判断methods 中的方法,获取一个能正确执行的,并将createXHRObject的引用指向这个方法。以后再使用这个方法的时候,不用去判断,直接自动获取正确的方法。这省去了频繁的ajax调用中浏览器的检测。

当然,这个方法看上去效率的提升不是特别明显,我之所以写上来,是因为能比较清晰的理解memoization是如何实现的。在递归调用的时候,memoization的威力才能更好的显现。

一个递归的例子

  1. function fib(n) {
  2. if (n < 2) {
  3. return n;
  4. }
  5. return fib(n - 1) + fib(n - 2);
  6. }

 这是一个经典的斐波纳契序列,fib(20) 会把fib这个方法执行21891次,如果是fib(40),这会执行331160281次。

再看看如何使用memoization来实现,

  1.  var iterMemoFib = (function() {
  2.     var cache = [1, 1];
  3.     var fib = function(n) {
  4.         if (n >= cache.length) {
  5.             //将一个递归转换成了一个
  6.             for (var i = cache.length; i <= n; i++) {
  7.                 cache[i] = cache[i - 2] + cache[i - 1];
  8.             }
  9.         }
  10.         return cache[n-1];
  11.     }
  12.     return fib;
  13. })();

将Function的原型扩展memoize unmemoize 方法,这样你可以对任何函数实现memoize和解除memoize,当然,这个方法要慎,对一些不是频繁执行的函数,没必要缓存:

  1. Function.prototype.memoize = function() {
  2.     var pad  = {};
  3.     var self = this;
  4.     var obj  = arguments.length > 0 ? arguments[i] : null;
  5.  
  6.     var memoizedFn = function() {
  7.         // 把参数作为数组保存,作为键,把函数执行的结果作为值缓存起来
  8.         var args = [];
  9.         for (var i = 0; i < arguments.length; i++) {
  10.             args[i] = arguments[i];
  11.         }
  12.         if (!(args in pad)) {
  13.             pad[args] = self.apply(obj, arguments);
  14.         }
  15.         return pad[args];
  16.     }
  17.     memoizedFn.unmemoize = function() {
  18.         return self;
  19.     }
  20.     return memoizedFn;
  21. }
  22. Function.prototype.unmemoize = function() {
  23.     alert("Attempt to unmemoize an unmemoized function.");
  24.     return null;
  25. }
  26.  

使用方法:

fib.memoize();

参考文档:

  1. Memoizing functions in JavaScript
  2. JavaScript Memoization
  3. 提升JS性能:将递归转换为迭代
  4. MemoizationFrom Wikipedia, the free encyclopedia