定义:
代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。
举个例子来说明吧。
小明遇到了他的百分百女孩,暂且把他的女神称呼为 A,小明决定给A送一束花表白。刚好小明和A有一个共同的朋友B,于是内向的小明决定让B来代替自己完成送花这件事。
let Flower = function(){};
let xiaoming = {
sendFlower: (target)=>{
let flower = new Flower();
targe.receiveFlower(flower);
}
};
let A = {
receiveFlower: (flower)=>{
console.log('收到花'+flower);
}
};
let B = {
receiveFlower: (flower)=>{
A.receiveFlower(flower);
}
};
xiaoming.sendFlower(B);
此处的代理模式看着毫无用处,它所做的值是把请求简单的转交给本体。
现在我们改变故事背景,假设当A心情好的时候收到花,小明表白成功几率有60%,反之,成功几率无限趋近于0。而B比较了解A,所以小明把花交给B,B会监听A的心情变化,然后选择A心情好多时候把花转交给A。
let Flower = function(){};
let xiaoming = {
sendFlower: (target)=>{
let flower = new Flower();
targe.receiveFlower(flower);
}
};
let A = {
receiveFlower: (flower)=>{
console.log('收到花'+flower);
},
listernGoodMood: (fn)=>{
fn();
}
};
let B = {
receiveFlower: (flower)=>{
A.listernGoodMood(function(){
A.receiveFlower(flower);
})
}
};
xiaoming.sendFlower(B);
代理模式的类型
保护代理和虚拟代理
以上面例子来说,如果送花的人中年龄太大或者太穷,这种请求就可以在代理 B 出被拒绝掉。这种代理就叫做保护代理
。
现实中的花价格不菲,在程序世界中,类似 new Flower 是一种代价昂贵的操作,那么我们可以把 new Flower 的操作交给代理 B 去执行,B 会选择在 A心情好的时候去执行 new Flower,这种代理叫做虚拟代理
。他会把一些开销很大的对象,延迟到真正需要它的时候才去创建。
利用虚拟代理
实现图片预加载,当图片还未请求到时,先用一个占位图片来代替。
let myImage = (function(){
let imgNode = document.createElement('img');
document.body.appendChild( imgNode );
return {
setSrc: (src)=>{
imgNode.src = src;
}
}
})();
let proxyImage = (function(){
let img = new Image;
img.onload = ()=>{
myImage.setSrc(this.src);
}
return{
setSrc: (src)=>{
myImage.setSrc('file:// /C:/User/chinaoly/Desktop/load.jpg');
img.src = src;
}
}
})();
proxyImage.setSrc
缓存代理
缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传递进来的参数跟之前一致,则可以直接返回前面存储的运算结果。
// 计算乘积
let mult = ()=>{
let a = 1;
for(let i = 0; i<arguements.length; i++){
a = a*arguements[i];
}
return a;
}
let proxyMult = ()=>{
let cache = {};
return function(){
let args = Array.prototype.join.call(arguements,',');
if(args in cache){
return cache[args];
}
return cache[args] = mult.apply(this, arguements);
}
}
proxyMult(1,2,3,4); //24
proxyMult(1,2,3,4); //24 第二次调用时本体 mult 并没有执行
同理我们也可以缓存 Ajax 异步请求数据,比如在分页数据中,如果对数据实时性没要求,可以对请求过的数据做缓存。
小结:
代理模式包括很多小类,在 JavaScript 开发中最常用的就是虚拟代理和缓存代理,在编写代码时,不需要预先猜测是否需要使用代理模式,当真正发现不方便直接访问某个对象时,在编写代理也不迟