# 代理模式
为一个对象提供一个代用品或占位符,以便控制对它的访问。
代理模式确实很方便,通常如果面临一些很大开销的操作,就可以并采用虚拟代理的方式延迟到需要它的时候再去创建,比如懒加载操作。
在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用。代理可以帮客户过滤掉一些请求并且把一些开销大的对象,延迟到真正需要它时才创建。
在 JS 中比较典型的代理有图片懒加载,合并 http 请求,以及缓存计算乘积。
# 送花的例子
class Flower {
constructor(name) {
this.name = name;
}
}
// 送花人 小明
let xiaoming = {
name: '小明',
sendFlower(target) {
target.receiveFlower(this.name)
}
}
// 代理B
let B = {
receiveFlower(customer) {
// 当然要等小红好心情时才送花,也在送花时,才创建花
A.listenGoodMood(() => {
A.receiveFlower(new Flower(customer + '的花'))
})
}
}
// 心仪对象 小红
let A = {
name: '小红',
receiveFlower(flower) {
console.log(this.name + '收到:' + flower.name)
},
listenGoodMood(fn) {
setTimeout(() => {
fn()
}, 1000)
}
}
xiaoming.sendFlower(B) // 小红收到:小明的花
# 图片懒加载
下面是一个图片懒加载的例子,我们加先加载默认图片,等真实图片加载完之后再替换默认图片。
const createImage = (function() {
const img = document.createElement('img');
document.body.appendChild(img);
return function(src) {
img.src = src;
}
})();
const proxyImage = function(fn) {
const image = new Image();
const defaultImg = 'https://rs.vip.miui.com/vip-resource/prod/mio/v136/static/media/lazyLoad.a10ffbd7.png';
return function(src) {
fn(defaultImg);
// 这里加一个延迟,可以更好的看到图片替换的过程。
setTimeout(function() {
image.src = src;
image.onload = function() {
fn(src);
};
}, 2000);
};
};
const proxy = proxyImage(createImage);
proxy('https://pic1.zhimg.com/80/v2-ec33fcec249a9cabab61b14436432bf0_r.jpg');
# ES6的Proxy
Proxy 是 ES6 提供的专门以代理角色出现的代理器,Vue 3.0 的响应式数据部分弃用了 Object.defineProperty,使用 Proxy 来代替它。
现在用Proxy
模拟一下另一种场景:
为了保护不及格的同学,课代表拿到全班成绩单后只会公示及格人的成绩。对考分有疑问的考生,复议后新分数比以前大10分才有权利去更新成绩
const list = {
'A': 100,
'B': 70,
'C': 50
}
const obj = new Proxy(list, {
get(target, key) {
if(target[key] > 60) {
console.log('考试及格')
return target[key]
} else {
console.log('不及格的成绩无法公示')
}
},
set(target, key, newVal) {
if(newVal - target[key] > 10) {
target[key] = newVal
console.log('修改成绩:success')
} else {
console.log('修改成绩:error')
}
}
})
obj.A; // 考试及格
obj.B; // 考试及格
obj.C; // 不及格的成绩无法公示
obj.A = 111; // success
obj.B = 20; // error