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

Javascript
javascript innerText和innerHtml应用
图像替换新技术 状态域方法
JavaScript 判断判断某个对象是Object还是一个Array
Extjs 几个方法的讨论
JavaScript 学习笔记(十五)
javascript 匿名函数的理解(透彻版)
Jquery 常用方法经典总结
jquery 批量上传图片实现代码
javascript中的array数组使用技巧
详细讲解JS节点知识
javascript让setInteval里的函数参数中的this指向特定的对象
javaScript 关闭浏览器 (不弹出提示框)
对字符串进行HTML编码和解码的JavaScript函数
javascript 三种编解码方式
js左侧多级菜单动态的解决方案
JavaScript 学习笔记(十六) js事件
JavaScript面向对象之静态与非静态类
javascript两段代码,两个小技巧
js中鼠标滚轮事件详解(firefox多浏览器)
js实现的仿Photoshop鼠标滚轮控制输入框取值(修正兼容Chrome)

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


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 124 ::
收藏到网摘: 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