代理模式,顧名思義,就是A要對(duì)C做一件事情,讓B幫忙做(怎么聽起來(lái)怪怪的)。
// A
var A = function(){
this.talk = function(){
console.log("能帶我打dota2嗎");
}
};
//C
var C= function(){
this.B = new B();
this.talk = function(){
console.log("一個(gè)人打dota2好沒(méi)意思啊");
this.B.talk();
}
}
//我
var B = function(){
this.A = new A();
this.talk = function(){
console.log("A 讓我問(wèn)你");
this.A.talk();
}
}
//執(zhí)行
new C().talk();
//結(jié)果
/**
* 一個(gè)人打dota2好沒(méi)意思啊
* A 讓我問(wèn)你
* 能帶我打dota2嗎
*/
下面寫幾個(gè)常見(jiàn)的使用代理模式的例子
在網(wǎng)頁(yè)開發(fā)中,圖片的預(yù)加載是一種比較常用的技術(shù),如果直接給img標(biāo)簽節(jié)點(diǎn)設(shè)置src屬性的話,如果圖片比較大的話,或者網(wǎng)速相對(duì)比較慢的話,那么在圖片未加載完之前,圖片會(huì)有一段時(shí)間是空白的場(chǎng)景,這樣對(duì)于用戶體驗(yàn)來(lái)講并不好,那么這個(gè)時(shí)候我們可以在圖片未加載完之前我們可以使用一個(gè)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;
}
}
})();
// 調(diào)用方式
ProxyImage.setSrc("https://img.alicdn.com/tps/i4/TB1b_neLXXXXXcoXFXXc8PZ9XXX-130-200.png");
如上代碼所示,其中myImage 函數(shù)只負(fù)責(zé)做一件事,創(chuàng)建img元素加入到頁(yè)面中,其中的加載loading圖片交給代理函數(shù)ProxyImage 去做,當(dāng)圖片加載成功后,代理函數(shù)ProxyImage 會(huì)通知及執(zhí)行myImage 函數(shù)的方法,同時(shí)當(dāng)以后不需要代理對(duì)象的話,我們直接可以調(diào)用本體對(duì)象的方法即可。
代理模式還可以用在需要多次提交數(shù)據(jù)的地方,比如,有表格數(shù)據(jù),每一條數(shù)據(jù)前面有復(fù)選框按鈕,當(dāng)點(diǎn)擊復(fù)選框按鈕時(shí)候,需要獲取該id后需要傳遞給給服務(wù)器發(fā)送ajax請(qǐng)求,服務(wù)器端需要記錄這條數(shù)據(jù),去請(qǐng)求,如果我們每當(dāng)點(diǎn)擊一下向服務(wù)器發(fā)送一個(gè)http請(qǐng)求的話,對(duì)于服務(wù)器來(lái)說(shuō)壓力比較大,網(wǎng)絡(luò)請(qǐng)求比較頻繁,但是如果現(xiàn)在該系統(tǒng)的實(shí)時(shí)數(shù)據(jù)不是很高的話,我們可以通過(guò)一個(gè)代理函數(shù)收集一段時(shí)間內(nèi)(比如說(shuō)2-3秒)的所有id,一次性發(fā)ajax請(qǐng)求給服務(wù)器,相對(duì)來(lái)說(shuō)網(wǎng)絡(luò)請(qǐng)求降低了, 服務(wù)器壓力減少了;
// 本體函數(shù)
var mainFunc = function(ids) {
console.log(ids); // 即可打印被選中的所有的id
// 再把所有的id一次性發(fā)ajax請(qǐng)求給服務(wù)器端
};
// 代理函數(shù) 通過(guò)代理函數(shù)獲取所有的id 傳給本體函數(shù)去執(zhí)行
var proxyFunc = (function(){
var cache = [], // 保存一段時(shí)間內(nèi)的id
timer = null; // 定時(shí)器
return function(checkboxs) {
// 判斷如果定時(shí)器有的話,不進(jìn)行覆蓋操作
if(timer) {
return;
}
timer = setTimeout(function(){
// 在2秒內(nèi)獲取所有被選中的id,通過(guò)屬性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秒后需要給本體函數(shù)傳遞所有的id
// 清空定時(shí)器
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) {
// 給當(dāng)前增加一個(gè)屬性
this.setAttribute("isflag",1);
}else {
this.removeAttribute('isflag');
}
// 調(diào)用代理函數(shù)
proxyFunc(checkboxs);
}
})(i);
}
緩存代理可以為一些開銷大的運(yùn)算結(jié)果提供暫時(shí)的存儲(chǔ),在下次運(yùn)算時(shí),如果傳遞進(jìn)來(lái)的參數(shù)跟之前一致,則可以返回前面的運(yùn)算結(jié)果。
// 計(jì)算乘積
var mult = function(){
var a = 1;
for( var i = 0, l = arguments.length; i < l; i++){
a = a * arguments[i];
}
return a;
};
// 計(jì)算加和
var plus = function () {
var a = 0;
for( var i = 0, l = arguments.length; i < l; i++ ){
a += arguments[i];
}
return a;
};
// 創(chuàng)建緩存代理的工廠
var createProxyFactory = function( fn ){
var cache = {}; // 緩存 - 存放參數(shù)和計(jì)算后的值
return function(){
var args = Array.prototype.join.call(arguments, "-");
if( args in cache ){ // 判斷出入的參數(shù)是否被計(jì)算過(guò)
console.log( "使用緩存代理" );
return cache[args];
}
return cache[args] = fn.apply( this, arguments );
}
};
// 創(chuàng)建代理
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