代理模式,顾名思义,就是A要对C做一件事情,让B帮忙做(怎么听起来怪怪的)。
// A
var A = function(){
this.talk = function(){
console.log("能带我打dota2吗");
}
};
//C
var C= function(){
this.B = new B();
this.talk = function(){
console.log("一个人打dota2好没意思啊");
this.B.talk();
}
}
//我
var B = function(){
this.A = new A();
this.talk = function(){
console.log("A 让我问你");
this.A.talk();
}
}
//执行
new C().talk();
//结果
/**
* 一个人打dota2好没意思啊
* A 让我问你
* 能带我打dota2吗
*/
下面写几个常见的使用代理模式的例子
在网页开发中,图片的预加载是一种比较常用的技术,如果直接给img标签节点设置src属性的话,如果图片比较大的话,或者网速相对比较慢的话,那么在图片未加载完之前,图片会有一段时间是空白的场景,这样对于用户体验来讲并不好,那么这个时候我们可以在图片未加载完之前我们可以使用一个loading加载图片。
//使用代理模式的写法
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("http://img.lanrentuku.com/img/allimg/1212/5-121204193Q9-50.gif");
img.src = src;
}
}
})();
// 调用方式
ProxyImage.setSrc("https://img.alicdn.com/tps/i4/TB1b_neLXXXXXcoXFXXc8PZ9XXX-130-200.png");
如上代码所示,其中myImage 函数只负责做一件事,创建img元素加入到页面中,其中的加载loading图片交给代理函数ProxyImage 去做,当图片加载成功后,代理函数ProxyImage 会通知及执行myImage 函数的方法,同时当以后不需要代理对象的话,我们直接可以调用本体对象的方法即可。
代理模式还可以用在需要多次提交数据的地方,比如,有表格数据,每一条数据前面有复选框按钮,当点击复选框按钮时候,需要获取该id后需要传递给给服务器发送ajax请求,服务器端需要记录这条数据,去请求,如果我们每当点击一下向服务器发送一个http请求的话,对于服务器来说压力比较大,网络请求比较频繁,但是如果现在该系统的实时数据不是很高的话,我们可以通过一个代理函数收集一段时间内(比如说2-3秒)的所有id,一次性发ajax请求给服务器,相对来说网络请求降低了, 服务器压力减少了;
// 本体函数
var mainFunc = function(ids) {
console.log(ids); // 即可打印被选中的所有的id
// 再把所有的id一次性发ajax请求给服务器端
};
// 代理函数 通过代理函数获取所有的id 传给本体函数去执行
var proxyFunc = (function(){
var cache = [], // 保存一段时间内的id
timer = null; // 定时器
return function(checkboxs) {
// 判断如果定时器有的话,不进行覆盖操作
if(timer) {
return;
}
timer = setTimeout(function(){
// 在2秒内获取所有被选中的id,通过属性isflag判断是否被选中
for(var i = 0,ilen = checkboxs.length; i < ilen; i++) {
if(checkboxs[i].hasAttribute("isflag")) {
var id = checkboxs[i].getAttribute("data-id");
cache[cache.length] = id;
}
}
mainFunc(cache.join(',')); // 2秒后需要给本体函数传递所有的id
// 清空定时器
clearTimeout(timer);
timer = null;
cache = [];
},2000);
}
})();
var checkboxs = document.getElementsByClassName("j-input");
for(var i = 0,ilen = checkboxs.length; i < ilen; i+=1) {
(function(i){
checkboxs[i].onclick = function(){
if(this.checked) {
// 给当前增加一个属性
this.setAttribute("isflag",1);
}else {
this.removeAttribute('isflag');
}
// 调用代理函数
proxyFunc(checkboxs);
}
})(i);
}
缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传递进来的参数跟之前一致,则可以返回前面的运算结果。
// 计算乘积
var mult = function(){
var a = 1;
for( var i = 0, l = arguments.length; i < l; i++){
a = a * arguments[i];
}
return a;
};
// 计算加和
var plus = function () {
var a = 0;
for( var i = 0, l = arguments.length; i < l; i++ ){
a += arguments[i];
}
return a;
};
// 创建缓存代理的工厂
var createProxyFactory = function( fn ){
var cache = {}; // 缓存 - 存放参数和计算后的值
return function(){
var args = Array.prototype.join.call(arguments, "-");
if( args in cache ){ // 判断出入的参数是否被计算过
console.log( "使用缓存代理" );
return cache[args];
}
return cache[args] = fn.apply( this, arguments );
}
};
// 创建代理
var proxyMult = createProxyFactory( mult ),
proxyPlus = createProxyFactory( plus );
console.log( proxyMult( 1, 2, 3, 4 ) ); // 输出: 24
console.log( proxyMult( 1, 2, 3, 4 ) ); // 输出: 缓存代理 24
console.log( proxyPlus( 1, 2, 3, 4 ) ); // 输出: 10
console.log( proxyPlus( 1, 2, 3, 4 ) ); // 输出: 缓存代理 10