一.生活场景
明星都有经纪人作为代理。如果想请明星来办一场商业演出,只能联系他的经纪人。经纪人会把商业演出的细节和报酬都谈好之后,再把合同交给明星签。
二.定义
代理模式 :为一个对象提供一个代用品或占位符,以便控制对它的访问。
- 虚拟代理: 把一些开销很大的对象,延迟到真正需要它的时候才去创建。
- 缓存代理: 缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传递进来的参数跟之前一致,则可以直接返回前面存储的运算结果。
三.应用场景
1.图片预加载(利用虚拟代理)
当图片过大或者网络不佳时,图片预加载是一种常用的技术,如果直接给某个 img 标签节点设置 src 属性,,图片的位置往往有段时间会是一片空白。常见的做法是先用一张loading 图片占位,然后用异步的方式加载图片,等图片加载好了再把它填充到 img 节点里。
- 不用代理实现:
var myImage = (function () {
var imgNode = document.createElement('img');
document.body.appendChild(imgNode);
return {
setSrc: function (src) {
imgNode.src = src;
}
}
})();
myImage.setSrc('http://jsmeng.top/music/photo/k/000GGDys0yA0Nk.jpg');
- 虚拟代理实现
var myImage = (function () {
var imgNode = document.createElement('img');
document.body.appendChild(imgNode);
return {
setSrc: function (src) {
imgNode.src = src;
}
}
})();
var proxyImage = (function () {
var img = new Image;
img.onload = function () {
myImage.setSrc(this.src);
}
return {
setSrc: function (src) {
myImage.setSrc('file://C:/Users/svenzeng/Desktop/loading.gif');
img.src = src;
}
}
})();
proxyImage.setSrc('http://jsmeng.top/music/photo/k/000GGDys0yA0Nk.jpg');
运用代理模式来实现图片预加载,巧妙地将创建图片与预加载逻辑分离,并且在未来如果不需要预加载,只要改成请求本体代替请求代理对象就行。
2.计算乘积(利用缓存代理)
当一些计算非常耗费性能和时间时,我们可以缓存每次计算的结果,从而避免相同运算带来的时间浪费。
/***********************创建一个求乘积的函数**************************/
var mult = function () {
console.log('开始计算乘积');
var a = 1;
for (var i = 0, l = arguments.length; i < l; i++) {
a = a * arguments[i];
}
return a;
};
/***********************缓存代理函数**************************/
var proxyMult = (function () {
var cache = {};
return function () {
var args = Array.prototype.join.call(arguments, ',');
if (args in cache) {
return cache[args];
}
return cache[args] = mult.apply(this, arguments);
}
})();
proxyMult(1, 2, 3, 4); // 输出:24
proxyMult(1, 2, 3, 4); // 输出:24
四.总结
对于开发者而言,代理只是在本体之前加了一层处理,并不影响本地的算法,当我们不需要代理时,只需要注释代理代码,直接访问本体就可。
对于用户来说,代理的过程是透明的,用户并不清楚代理和本体的区别,这样做有两个好处。
- 用户可以放心地请求代理,他只关心是否能得到想要的结果。
- 在任何使用本体的地方都可以替换成使用代理。
我们在编写业务代码的时候,往往不需要去预先猜测是否需要使用代理模式。当真正发现不方便直接访问某个对象的时候,再编写代理也不迟。