memoize使用实例之创建XHR

首先看看创建XHR最简单的方法:

function createXHR() { // Factory method.  
    var methods = [  
        function() { return new XMLHttpRequest(); },  
        function() { return new ActiveXObject('Msxml2.XMLHTTP'); },  
        function() { return new ActiveXObject('Microsoft.XMLHTTP'); }  
    ];  
    var xhr;  
    for (var i = 0, len = methods.length; i < len; i++) {  
        try {  
            xhr = methods[i]();  
        } catch(e) {  
            continue;  
        }  
        // If we reach this point, method[i] worked.  
        return xhr;  
    }  
    throw new Error('Could not create an XHR object.');  
}  

我们调用createXHR函数来发起一个ajax请求,该函数会在内部遍历查找当前浏览器可用的xhr类型,然后返回。但显然每次都要循环一遍是没有必要的,能否让函数记住上一次返回的结果呢。

 在Pro Javascript design patterns一书里,可以看到这样的解决方法:

function createXHR2() {  
    var methods = [  
        function() { return new XMLHttpRequest(); },  
        function() { return new ActiveXObject('Msxml2.XMLHTTP'); },  
        function() { return new ActiveXObject('Microsoft.XMLHTTP'); }  
    ];  
    var xhr  
    for (var i = 0, len = methods.length; i < len; i++) {  
        try {  
            xhr = methods[i]();  
        } catch(e) {  
            continue;  
        }  
        createXHR2 = function() {// cache it  
            return xhr;  
        }  
        return methods[i];  
    }  
    throw new Error('Could not create an XHR object.');  
}  

可以看到14行的作用是,在函数第一次执行之后,把函数自身给替换了,当函数第二次执行时,直接就是return xhr;,这种做法使得函数具有了记忆功能。

 很巧妙的做法,但这样做的代价是,让一个函数多实现了一个它本不该有的功能,即cache功能,对于函数功能单一性的原则说,这种做法算不上完美。

 可能经常会碰到这种需要记忆的函数,这种机制需要被抽象出来:

(以下代码来源于 Memoization in JavaScript,略有改动)

function asArray(quasiArray, start) {  
    var r = [];  
    for (var i = (start || 0); i < quasiArray.length; i++)  
        r.push(quasiArray[i]);  
    return r;  
}  
  
Function.prototype.memoize = function(scope) {  
    var cache  = {};  
    var self = this;  
    scope = scope !== undefined ? scope : null;  
  
    var memoizedFn = function() {  
        var key = asArray(arguments).toString();  
  
        if (!(key in cache)) {  
            cache[key] = self.apply(scope, arguments);  
        }  
  
        return cache[key];  
    };  
  
    memoizedFn.unmemoize = function() {  
        return self;  
    };  
  
    return memoizedFn;  
};  

注:arguments是类似数组的东东,有部分数组特性,比如arguments[0],但没有toString()之类数组内置方法,所以需要用asArray将其转换为数组。

var memoizedCreateXHR = createXHR.memoize();  
  
console.info(memoizedCreateXHR());  

关于memoization的更多应用,可以参考

speed-up-your-javascript-part-2/

One-Line JavaScript Memoization

Timed Memoization 

 

posted @ 2011-02-28 18:26  aj3423  阅读(316)  评论(0编辑  收藏  举报