定义:
为其他对象提供一种代理以控制对这个对象的访问。
何时使用:想在访问一个类时做一些控制。
如何解决:增加中间层。
应用实例:
1、明星使用经纪人做代理,请明星演出,只能联系他的经纪人,经纪人将所有演出细节和报酬谈妥之后,再将合同给明星签字。
2、买火车票不一定在火车站买,也可以去代售点。
如下图所示,就是在中间增加一个中间层做代理,例如es6的Proxy就是一个很好地例子
使用场景:
按职责来划分,通常有以下使用场景:
1、远程代理。
2、虚拟代理。
3、Copy-on-Write 代理。
4、保护(Protect or Access)代理。
5、缓存代理。
6、防火墙(Firewall)代理。
7、同步化(Synchronization)代理。
8、智能引用(Smart Reference)代理。
本文主要讲述的是js中常用的两种代理模式------> 虚拟代理和缓存代理
1、我们先来看如何使用虚拟代理实现图片的懒加载
//创建img对象,设置setSrc方法
let myImg = {
setSrc(imgNode, src){
imgNode.src = src;
}
}
//创建代理对象,处理真正的逻辑
let ProxyImg = {
setSrc(imgNode, src){
myImg.setSrc(imgNode, 'file://image/loading.gif');
let img = new Image();
img.onload = () => {
myImg.setSrc(imgNode, src);
}
img.src = src;
}
}
let imgNode = document.createElement('img');
imgSrc = 'https://upload.jianshu.io/users/upload_avatars/1413261/a0f9887a-
24f8-408c-bfd1-2975924e8f02.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/80/h/80/format/webp'
document.body.appendChild(imgNode);
ProxyImg.setSrc(imgNode, imgSrc);
上面的代码比较粗糙的解释了代理模式的作用,下面进行代码的优化
let myImg = (() =>{
let imgNode = document.createElement('img');
document.body.prepend(imgNode);
return {
setSrc(src){
imgNode.src = src;
}
}
})()
let ProxyImg = ((src) => {
let img = new Image();
img.onload = () => {
myImg.setSrc(img.src);
}
return {
setSrc(src){
myImg.setSrc('https://b-gold-cdn.xitu.io/v3/static/img/logo.a7995ad.svg');
img.src = src;
}
}
})()
imgSrc = 'https://upload.jianshu.io/users/upload_avatars/1413261/a0f9887a-
24f8-408c-bfd1-2975924e8f02.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/80/h/80/format/webp'
ProxyImg.setSrc(imgSrc);
案例小结
可以看出代码优化之后,结构更加清晰。
使用匿名函数自自执行,一方面可以不对外暴露接口与方法
另一方面使得创建dom节点与加载进行异步分离,某种程度上实现代码的解耦。
myImg对象负责创建dom节点,里面的setSrc负责渲染真正图片
代理对象proxyImg负责创建img对象,设置初始图片路径src,等图片onload方法执行之后,便开始将传入的src替换初始图片的src,从而实现图片占位的效果。
2、使用缓存代理实现计算结果的缓存
// 计算乘积
let mult = function(){
let a = 1;
for(let i = 0; i < arguments.length; i++){
a = a * arguments[i];
}
console.log(a)
return a;
}
// mult(1, 2);
// 创建缓存代理的工厂
let createProxyFactory = function(fn){
let cache = {};
return function(){
let args = Array.prototype.join.call(arguments, ','); // '1,2,3,4'
if(args in cache){
return cache[args];
}
return cache[args] = fn.apply(this, arguments);
}
}
let proxyMult = createProxyFactory(mult);
proxyMult(1, 2, 3, 4);
// 有了第一次cache对象中的缓存的结果,第二次直接返回
proxyMult(1, 2, 3, 4);
本次案例,第一次执行proxyMult的时候,返回一个function,当传入参数1234调用第一次的时候,缓存了一个计算记过{'1234', 24},当第二次传入同样的参数,便可以从cache对象中找到第一次的计算结果,直接返回即可,这样减少了计算。
案例小结:通过传入高阶函数这种更加灵活的方式,可以为各种计算方法创建缓存代理。现在这些方法被当做参数传入一个专门用于创建缓存代理的工厂中,这样一来,我们就可以为乘法、加法、减法等创建缓存代理。
大家可以思考一下缓存代理 如何用于ajax异步请求数据,同一页的数据理论上只需要去后台 领取一次,这些已经拉去到的数据在某个地方被缓存之后,下次再请求统同一页的时候,便可以直接使用之前的数据。
参考曾参的《JavaScript设计模式与开发实践》
网友评论