這裏有一份簡潔的前端知識體系等待你查收,看看吧,會有驚喜哦~若是以爲不錯,懇求star哈~前端
代理是一個對象,跟本體對象具備相同的接口,以此達到對本體對象的訪問控制。git
簡單言之,本體對象只注重業務邏輯的實現,代理則控制本體對象的實例化(什麼時候實例化、什麼時候被使用)。github
代理模式的優勢在於:代理對象能夠代替本體對象被實例化,此時本體對象未真正實例化,等到合適時機再實例化。緩存
代理模式能夠延遲建立開銷很大的本體對象,他會把本體的實例化推遲到有方法被調用時。bash
// 聲明女孩對象
var girl = function (name) {
this.name = name;
};
// 聲明男孩對象
var boy = function (girl) {
this.girl = girl;
this.sendGift = function (gift) {
alert("Hi " + girl.name + ", 男孩送你一個禮物:" + gift);
}
};
// 聲明代理對象
var proxyObj = function (girl) {
this.girl = girl;
this.sendGift = function (gift) {
(new boy(girl)).sendGift(gift); // 替dudu送花咯
}
};
var proxy = new proxyObj(new girl("花花"));
proxy.sendGift("999朵玫瑰");
複製代碼
如上代碼,girl是一個被送禮物的對象,boy是送禮物的對象,他保存了girl這個屬性,還有一個送禮物的方法sendGift,而後他經過proxyObj去完成這件事,proxyObj就是代理,他把boy的禮物送給了girl,所以proxyObj一樣須要保存girl的屬性,同時也有sendGift方法,該方法實例化本體對象boy並調用了boy的sendGift方法,完成了boy送girl禮物的這個過程。app
在前端開發中,使用圖片是很是常見的場景,若是直接給img標籤設置src屬性,若是圖片過大,或網速比較慢,圖片在加載過程當中會有一段時間的空白,用戶體驗很差。函數
傳統的解決方法是:在圖片未加載完成以前,使用一個loading圖標做爲佔位符,等圖片完成加載後,再使用真實的圖片地址替代loading圖標。以下:性能
// 不使用代理的預加載圖片函數以下
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 = "http://img.lanrentuku.com/img/allimg/1212/5-121204193R0.gif";
img.src = src;
}
}
})();
// 調用方式
myImage.setSrc("https://www.baidu.com/img/bd_logo1.png");
複製代碼
如上代碼,這是使用通常的編碼方式實現圖片的預加載技術的方案,首先建立imgNode元素,而後調用myImage.setSrc該方法的時候,先給圖片一個預加載圖片,當圖片加載完的時候,再給img元素賦值。ui
這種方案是能夠實現功能,但也有比較明顯的缺陷:耦合性過高,myImage函數違背了面向對象設計原則中的單一職責原則,同時完成了建立img,設置loading加載狀態等多個任務。this
此時就可使用代理模式來實現~~~
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-121204193R0.gif");
img.src = src;
}
}
})();
// 調用方式
ProxyImage.setSrc("https://www.baidu.com/img/bd_logo1.png");
複製代碼
如上代碼,myImage 函數只負責作一件事,建立img元素加入到頁面中,其中的加載loading圖片交給代理函數ProxyImage 去作,當圖片加載成功後,代理函數ProxyImage 會通知及執行myImage 函數的方法,同時當之後不須要代理對象的話,咱們直接能夠調用本體對象的方法便可。
代理模式跟本體對象具備相同的對外接口,有兩個好處: 1、用戶能夠放心地請求代理,不須要了解代理的實現過程,只要結果符合預期便可。若是不須要代理對象了,能夠換成調用本體對象的該方法 2、在任何使用本體對象的地方,均可以使用代理替換。
最後,強調一點,主體對象跟代理對象也能夠都返回一個匿名函數,這樣也認爲他們具備相同的接口。
對第一次運行的結果進行緩存,當再一次運行相同運算的時候,直接從緩存裏面取,避免重複運算,若是運算很是複雜的話,對性能很耗費,那麼使用緩存對象能夠提升性能。如下是一個簡單的例子:
var mult = function(){
var a = 1;
for(var i = 0,ilen = arguments.length; i < ilen; i+=1) {
a = a*arguments[i];
}
return a;
};
// 計算加法
var plus = function(){
var a = 0;
for(var i = 0,ilen = arguments.length; i < ilen; i+=1) {
a += arguments[i];
}
return a;
}
// 代理函數
var proxyFunc = function(fn) {
var cache = {}; // 緩存對象
return function(){
var args = Array.prototype.join.call(arguments,',');
if(args in cache) {
return cache[args]; // 使用緩存代理
}
return cache[args] = fn.apply(this,arguments);
}
};
var proxyMult = proxyFunc(mult);
console.log(proxyMult(1,2,3,4)); // 24
console.log(proxyMult(1,2,3,4)); // 緩存取 24
var proxyPlus = proxyFunc(plus);
console.log(proxyPlus(1,2,3,4)); // 10
console.log(proxyPlus(1,2,3,4)); // 緩存取 10
複製代碼
如上代碼就是網上常見的加法和乘法的運算。經過緩存代理,能夠減小沒必要要的運算量。