关键在于代理,也就是不方便直接访问目标对象或者不满足要求的时候,提供一个替身来控制对目标对象的访问。
常见的代理有保护代理、缓存代理、虚拟代理。JS 无法判断谁访问了某个对象,不容易实现保护代理(控制不同权限对象对目标对象的访问)。后两种可实现,很常用。
区分 3 种代理主要看用途,保护代理控制的是操作的权限,虚拟代理控制的是操作的时机,缓存代理控制的是操作的结果。
虚拟代理和缓存代理主要解决的问题都是一些开销较大的操作,延迟执行,或者缓存起来。
// 图片预加载 - 虚拟代理
var myImage = (function() {
var imgNode = document.createElement('img');
document.body.appendChild(imgNode);
return {
setSrc(src) {
imgNode.src = src;
}
}
})();
var proxyImage = (function() {
var img = new Image;
img.onload = function() {
// 等到实际的目标图标加载完之后,再将文档中的图标地址切换成目标图标地址。
myImage.setSrc(this.src);
}
return {
setSrc(src) {
// 调用 proxyImage.setSrc 设置目标图标地址的同时预加载一个本地的 加载中 图标,增加用户体验。
myImage.setSrc('loading.gif');
img.src = src;
}
}
})();
// 计算乘积 - 缓存代理
var mult = function() {
console.log('开始计算乘积');
var a = 1;
for (let i = 0, l = arguments.length; i < l; i++) {
a *= arguments[i];
}
return a;
}
console.log(mult(2, 3, 4));
console.log(mult(2, 3, 4, 6));
console.log('--------------');
var proxyMult = (function() {
var cache = {};
return function() {
const key = [].join.call(arguments, ',');
if (key in cache) {
return cache[key];
}
return cache[key] = mult.apply(this, arguments);
}
})();
console.log(proxyMult(2, 3, 4));
console.log(proxyMult(2, 3, 4, 6, 7));
console.log('----------------------');
// 进一步可以使用 高阶函数 抽象出一个 创建代理的工厂函数
// 也就是将上面不变的部分( 对源函数的 apply 调用 )抽象出来
var createProxyFactory = function(fn) {
var cache = {};
return function() {
const key = [].join.call(arguments, ',');
if (key in cache) {
return cache[key];
}
return cache[key] = fn.apply(this, arguments);
}
};
var proxyMultF = createProxyFactory(mult);
console.log(proxyMult(2, 3, 4));
console.log(proxyMult(2, 3, 4, 5, 9, 9));