代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。es6
按职责来划分的话,分为如下8种代理:数组
一、缓存代理缓存
二、虚拟代理app
三、写时复制Copy-on-Write 代理函数
四、保护(Protect or Access)代理ui
五、Cache代理this
六、防火墙(Firewall)代理spa
七、同步化(Synchronization)代理prototype
八、智能引用(Smart Reference)代理设计
在js中经常使用到的是缓存代理和虚拟代理
// 不使用代理的预加载图片函数以下
var myImage = (function(){
var imgNode = document.createElement("img");
document.body.appendChild(imgNode);
var img = new Image();
img.onload = function(){
imgNode.src = this.src;
};
return {
setSrc: function(src) {
imgNode.src = "loading.gif";
img.src = src;
}
}
})();
// 调用方式
myImage.setSrc("pic.png");
复制代码
var myImage = (function(){
var imgNode = document.createElement("img");
document.body.appendChild(imgNode);
return {
setSrc: function(src) {
imgNode.src = src;
}
}
})();
// 代理模式
var ProxyImage = (function(){
var img = new Image();
img.onload = function(){
myImage.setSrc(this.src);
};
return {
setSrc: function(src) {
myImage.setSrc("loading.gif");
img.src = src;
}
}
})();
// 调用方式
ProxyImage.setSrc("pic.png");
复制代码
一、建立img标签
二、插入img标签
三、建立img对象
四、书写onloading方法
五、返回设置图片对象。
缺点:
一、代码耦合度比较大,一个函数内负责作了几件事情。未知足面向对象设计原则中单一职责原则;
二、当某个时候不须要图片预加载的时候,须要从myImage 函数内把代码删掉,这样代码耦合性过高。
一、myImage中建立img标签
二、myImage中插入img标签
三、myImage中返回设置imgNode的src方法
四、ProxyImage中建立img对象
五、ProxyImage中书写onload方法
六、ProxyImage中返回设置图片的方法。
优势:
一、myImage 函数只负责作一件事。建立img元素加入到页面中,其中的加载loading图片交给代理函数ProxyImage 去作。
二、加载成功之后,代理函数ProxyImage 会通知及执行myImage 函数的方法。
三、当之后不须要代理对象的话,咱们直接能够调用本体对象的方法便可
缓存代理,就是将前面使用的值缓存下来,后续还有使用的话,就直接拿出来用。
var add = function(){
var sum = 0
for(var i = 0, l = arguments.length; i < l; i++){
sum += arguments[i]
}
return sum
}
var proxyAdd = (function(){
var cache = {} //缓存运算结果的缓存对象
return function(){
var args = Array.prototype.join.call(arguments)
if(cache.hasOwnProperty(args)){//等价 args in cache
console.log('使用缓存结果')
return cache[args]//直接使用缓存对象的“值”
}
console.log('计算结果')
return cache[args] = add.apply(this,arguments)//使用本体函数计算结果并加入缓存
console.log(cache);
}
})()
console.log(proxyAdd(1,2,3,4,5))
console.log(proxyAdd(1,2,3,4,5))
console.log(proxyAdd(1,2,3,4,5))
// 输出结果
计算结果
15
使用缓存结果
15
使用缓存结果
15
复制代码
二者的职责划分:add函数提供计算功能。proxyAdd提供访问add函数的功能和缓存功能。
const target = {}, handler = {}
const proxy = new Proxy(target, handler)
复制代码
target是目标对象,handler是处理函数。
var handler = {
get: function() {},
set: function() {},
apply: function() {},
construct: function() {},
}
复制代码
参数:目标对象、属性名、proxy实例自己
例子:
var person = {
name: "张三"
};
var proxy = new Proxy(person, {
get: function(target, property) {
if (property in target) {
return target[property];
} else {
throw new ReferenceError("Property \"" + property + "\" does not exist.");
}
}
});
proxy.name // "张三"
proxy.age // 抛出一个错误
复制代码
参数:目标对象、属性名、属性值、proxy实例自己
例子:
let validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
// 对于知足条件的 age 属性以及其余属性,直接保存
obj[prop] = value;
}
};
let a = {}
let person = new Proxy(a, validator);
person.age = 100;
a.age // 100
person.age = 'young' // 报错
person.age = 300 // 报错
复制代码
参数:目标对象,目标对象的上下文,参数组 例子:
var target = function () { return 'I am the target'; };
var handler = {
apply: function () {
return 'I am the proxy';
}
};
var p = new Proxy(target, handler);
p() // I am the proxy
复制代码
当调用p函数时,就会被proxy
拦截,返回I am the proxy
。
construct
方法用于拦截new
指令。
参数:目标对象、构造函数的参数对象 例子:
var P = new Proxy(function () {}, {
construct: function(target, args) {
console.log('called: ' + args.join(', '));
return { value: args[0] * 10 };
}
});
const p = new P(1);
// "called: 1"
p.value
// 10
复制代码
let myImage = (function(){
var imgNode = document.createElement("img");
document.body.appendChild(imgNode);
return {
setSrc: function(src) {
imgNode.src = src;
}
}
})();
let myImageProxy = new Proxy(myImage, {
apply(target, ctx, arguments) {
let img = new Image
img.onload = function(){
// 图片加载完成,正式加载图片
target.call(ctx, ...arguments)
}
// 图片未被载入时,加载一张提示图片
target.call(ctx, 'file://c:/loading.png')
img.src = arguments[0]
}
})
// 调用
let myImg = new myImageProxy(document)
myImg.setSrc('http://images/qq.jpg')
复制代码