狠狠的学 -- 代理模式

26 阅读2分钟

  关键在于代理,也就是不方便直接访问目标对象或者不满足要求的时候,提供一个替身来控制对目标对象的访问。

  常见的代理有保护代理、缓存代理、虚拟代理。JS 无法判断谁访问了某个对象,不容易实现保护代理(控制不同权限对象对目标对象的访问)。后两种可实现,很常用。

  区分 3 种代理主要看用途,保护代理控制的是操作的权限,虚拟代理控制的是操作的时机,缓存代理控制的是操作的结果

  虚拟代理和缓存代理主要解决的问题都是一些开销较大的操作,延迟执行,或者缓存起来。

// 图片预加载 - 虚拟代理
var myImage = (function() {
    var imgNode = document.createElement('img');
    document.body.appendChild(imgNode);
    return {
        setSrc(src) {
            imgNode.src = src;
        }
    }
})();
var proxyImage = (function() {
    var img = new Image;
    img.onload = function() {
        // 等到实际的目标图标加载完之后,再将文档中的图标地址切换成目标图标地址。
        myImage.setSrc(this.src);
    }
    return {
        setSrc(src) {
            // 调用 proxyImage.setSrc 设置目标图标地址的同时预加载一个本地的 加载中 图标,增加用户体验。
            myImage.setSrc('loading.gif');
            img.src = src;
        }
    }
})();
// 计算乘积 - 缓存代理
var mult = function() {
    console.log('开始计算乘积');
    var a = 1;
    for (let i = 0, l = arguments.length; i < l; i++) {
        a *= arguments[i];
    }
    return a;
}
console.log(mult(2, 3, 4));
console.log(mult(2, 3, 4, 6));
console.log('--------------');
var proxyMult = (function() {
    var cache = {};
    return function() {
        const key = [].join.call(arguments, ',');
        if (key in cache) {
            return cache[key];
        }
        return cache[key] = mult.apply(this, arguments);
    }
})();
console.log(proxyMult(2, 3, 4));
console.log(proxyMult(2, 3, 4, 6, 7));
console.log('----------------------');
// 进一步可以使用 高阶函数 抽象出一个 创建代理的工厂函数
// 也就是将上面不变的部分( 对源函数的 apply 调用 )抽象出来
var createProxyFactory = function(fn) {
    var cache = {};
    return function() {
        const key = [].join.call(arguments, ',');
        if (key in cache) {
            return cache[key];
        }
        return cache[key] = fn.apply(this, arguments);
    }
};
var proxyMultF = createProxyFactory(mult);
console.log(proxyMult(2, 3, 4));
console.log(proxyMult(2, 3, 4, 5, 9, 9));