今天我们来学习JavaScript常用的设计模式——代理模式
代理在现实生活中一般就是指代表授权方处理事务。在法律上,是指代理人,被授权方准许以其人名义,与第三者为法律行为的意思表示。因获得授权而为之的法律行为,可以对授权方直接发生法律上效力。
也就是说:当客户不方便直接访问某个对象的时候,可以提供一个代理对象供客户访问。代理对象对请求做出一系列处理之后,再将请求转交给本体对象。
# 定义
为⼀个对象提供⼀个代⽤品或占位符,以便控制对它的访问。替身对象可对请求预先进⾏处理, 再决定是否转交给本体对象。
代理模式也有很多种,比如保护代理和虚拟代理。保护代理用于控制不同权限对象目标对象的访问;虚拟代理是指把一些开销很大的对象,延迟到真正需要的时候才去创建。
# 应用场景
当我们不⽅便直接访问某个对象时,或不满⾜需求时,可考虑使⽤⼀个替身对象来控制该对象的访问。
下面我们以一个图片预加载的例子来看看虚拟代理模式:
# 使用前
先用一张加载中的图片占位,然后异步加载图片,等图片加载完成填充至img节点中
原生函数
const rawImage = (() => {
// 创建图片节点
const imgNode = document.createElement("img");
// 将图片节点添加到页面
document.body.appendChild(imgNode);
// 返回一个对象,提供一个接口
return {
// 对象中有一个方法,接受图片url
setSrc: (src) => {
// 将图片节点的src指向本地文件
imgNode.src = "./loading.gif";
// 创建一个新的图片
const img = new Image();
// 将图片的src指向传入的src
img.src = src;
// 当图片加载完毕,将图片节点的src改成img的src
img.onload = () => {
imgNode.src = this.src;
};
},
};
})();
rawImage.setSrc("http://xxx.gif");
违反了我们设计原则中的单一职责原则,什么操作都在原生函数中完成,所以我们需要解耦
# 使用后
原生函数仅提供 创建图片节点、设置图片链接 的功能
const rawImage = (() => {
const imgNode = document.createElement("img");
document.body.appendChild(imgNode);
return {
setSrc: (src) => {
imgNode.src = src;
},
};
})();
设置一个代理函数,通过代理来做一些操作,加载图片、设置加载图
const proxyImage = (() => {
// 创建新的图片
const img = new Image();
// 当图片加载完成,调用原生函数的修改src接口
img.onload = () => {
rawImage.setSrc(this.src);
};
return {
// 设置加载图片
setSrc: (src) => {
rawImage.setSrc("./loading.gif");
img.src = src;
},
};
})();
proxyImage.setSrc("http://xxx.gif");
这样写的好处是:使用代理函数来控制用户对原生函数的访问,并且可以在代理函数中进行一些额外的操作。