适配器
概念:实际接口和目标接口,通过适配器转换
典型例子:axios便是通过适配器从而达到适配浏览器和node环境
代理模式
像这种第三方代替我们访问目标对象的模式,就是代理模式。
代理器:Proxy
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截
const target = {}
const proxy = new Proxy(target,handler)
Proxy作为构造函数,有两个参数。
target所要代理的目标对象。
handler配置对象,对每个被代理的操作,提供一个对应的处理函数。
target目标对象,propKey属性名,value属性值,receiver实例本身
保护代理
实现保护代理时,考虑的首要方案就是 ES6 中的 Proxy。
// 规定礼物的数据结构由type和value组成
const present = {
type: '巧克力',
value: 60,
}
// 未知妹子
const girl = {
// 姓名
name: "小美",
// 自我介绍
aboutMe: "...",
// 年龄
age: 24,
// 职业
career: "teacher",
// 假头像
fakeAvatar: "xxxx",
// 真实头像
avatar: "xxxx",
// 手机号
// 礼物数组
presents: [],
// 拒收50块以下的礼物
bottomValue: 50,
// 记录最近一次收到的礼物
lastPresent: present,
};
//普通信息
const baseInfo = ["age", "career"];
//最隐私信息
const privateInfo = ["avatar", "phone"];
//用户
const user = {
isValidated: true,
isVIP: false,
};
const JuejinLover = new Proxy(girl, {
get: function (girl, key) {
if (baseInfo.indexOf !== -1 && !user.isValidated) {
alert("您还没有完成验证哦");
return;
}
if (user.isValidated && privateInfo.indexOf(key) && !user.isVIP) {
alert("只有Vip可以查询信息");
return;
}
},
set:function(girl,key,val){
// 最近一次送来的礼物会尝试赋值给lastPresent字段
if(key === 'lastPresent'){
if(val.value < girl.bottomValue){
alert('sorry,您的礼物被拒收了')
return
}
}
//如果没被拒收
girl.lastPresent = val
girl.presents = [...girl.presents,val]
}
});
由父元素对事件进行处理和分发、间接地将其作用于子元素,因此这种操作从模式上划分属于代理模式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事件代理</title>
</head>
<body>
<div id="father">
<a href="#">链接1</a>
<a href="#">链接2</a>
<a href="#">链接3</a>
<a href="#">链接4</a>
<a href="#">链接5</a>
</div>
</body>
<script>
const father = document.getElementById('father')
father.addEventListener('click',function(e){
if(e.target.tagName==='A'){
e.preventDefault()
alert(`我是${e.target.innerText}`)
}
})
</script>
</html>
实例,图片预加载:
操作虚拟image,加载好图片后,再赋值给实际图片
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>虚拟代理</title>
<style>
.imageContainer{
width: 300px;
height: 200px;
}
.imageContainer>img{
width: 100%;
}
</style>
</head>
<body>
<div class="imageContainer">
<img src="" id="image">
</div>
</body>
<script>
class PreLoadImage {
constructor(imgNode){
// 获取真实的DOM节点
this.imgNode = imgNode
}
//操作img的src属性
setSrc(imgUrl){
this.imgNode.src = imgUrl
}
}
class ProxyImage{
//占位置的url地址
static LOADIMG_URL = 'https://mnweb.mini1.cn/game/icons/icon1.png'
constructor(targetImage){
//目标image,即PreLoadImage实例
this.targetImage = targetImage;
}
// 该方法主要操作虚拟Image,完成加载
setSrc(targetUrl){
// 真实img节点初始化时展示的是一个占位图
this.targetImage.setSrc(ProxyImage.LOADIMG_URL)
// 创建一个帮我们加载图片的虚拟Image实例
const virtualImage = new Image()
// 监听目标图片加载的情况,完成时再将DOM上的真实img节点的src属性设置为目标图片的url
virtualImage.onload = () => {
this.targetImage.setSrc(targetUrl)
}
// 设置src属性,虚拟Image实例开始加载图片
virtualImage.src = targetUrl
}
}
const imageNode = document.getElementById('image');
const preLoaadImage = new PreLoadImage(imageNode)
const imagesExample = new ProxyImage(preLoaadImage)
imagesExample.setSrc('https://mnweb.mini1.cn/activity/miniweb/snow-activity/img/1-cartoon-content.45002b99.jpg')
</script>
</html>
缓存代理
“用空间换时间”
当我们需要用到某个已经计算过的值的时候,不想再耗时进行二次计算,而是希望能从内存里去取出现成的计算结果。
class bufferProxy {
// addAll方法会对你传入的所有参数做求和操作
addAll() {
console.log("进行了一次计算");
let result = 0;
let len = arguments.length;
for (let i = 0; i < len; i++) {
result += arguments[i];
}
return result;
}
// 为求和方法创建代理
ProxyAdd() {
let resultBuffer = {};
// return function () {
let argumentsStr = Array.prototype.join.call(arguments, ",");
if (argumentsStr in resultBuffer) {
return resultBuffer[argumentsStr];
}
return resultBuffer[argumentsStr] = this.addAll(...arguments);
};
// }
}
const bufferTest = new bufferProxy();
let a = bufferTest.ProxyAdd(1, 2, 3, 5, 8, 1)
console.log(a);
ProxyAdd 针对重复的入参只会计算一次,这将大大节省计算过程中的时间开销**。针对大量入参、做反复计算时,缓存代理的优势将得到更充分的凸显。**