學習JavaScript設計模式之代理模式,javascript設計模式
- 明星都有經紀人作為代理。如果請明星辦一場商演,只能聯絡其經紀人,經紀人會把商演的細節和報酬談好,再把合約交給明星簽。
一、定義
代理模式:為一個對象提供一個代用品或預留位置,以便控制對它的訪問。
代理分為:保護代理和虛擬代理
保護代理:用於控制不同許可權的對象對目標對象的訪問,在JavaScript中很難判斷誰訪問了某個對象,所以保護代理很難實現。
二、圖片預先載入(最常見的虛擬代理應用情境)
圖片預先載入是一種常用技術,如果直接給某個img標籤節點設定src屬性,由於圖片過大或者網路不佳,圖片的位置往往有段時間會有空白。常見的做法事先用一張loading圖片佔位,然後非同步載入圖片,待圖片載入完成,把其填充到img節點裡。
實現原理:
建立一個Image對象:var a = new Image();
定義Image對象的src: a.src = “xxx.gif”;
這樣做就相當於給瀏覽器緩衝了一張圖片。
可通過Image對象的complete屬性來檢測映像是否載入完成。每個Image對象都有一個complete屬性,當映像處於裝載過程中時,該屬性值false,當發生了onload、onerror、onabort中任何一個事件後,則表示映像裝載過程結束,此時complete屬性為true。
(1)非代理實現
var myImage = (function() { var imgNode = document.createElement("img"); document.body.appendChild(imgNode); var img = new Image(); img.onload = function() { imgNode.src = img.src; }; return { setSrc: function(src) { imgNode.src = "./images/loading.gif"; img.src = src; } }})();myImage.setSrc("./images/originImg.png");
(2)代理實現
// 建立圖片DOMvar 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); // this指向img!img載入完成後,將img.src傳遞給myImage }; return { setSrc: function(src) { myImage.setSrc("./images/loading.gif"); // loading img.src = src; } };})();proxyImage.setSrc("./images/originImg.png");
使用代理模式的好處:使每個函數功能單一,實現對象設計的“單一職責原則”!
三、檔案同步
假設我們在做一個檔案同步功能,當選中checkbox時候,它對應的檔案就會被同步到另外一台伺服器。
<body> <input type="checkbox" id="1" />檔案1 <input type="checkbox" id="2" />檔案2 <input type="checkbox" id="3" />檔案3 <input type="checkbox" id="4" />檔案4 <input type="checkbox" id="5" />檔案5 <input type="checkbox" id="6" />檔案6 </body>
沒選中一個checkbox就同步一次,顯然不太合理。因為在web開發中,最大的開銷就是網路請求。
解決方案:通過一個代理函數來收集一段時間之內的請求,然後一次性發給伺服器。
var synchronousFile = function(id) { console.log("開始同步檔案,id為:" + id);};var proxySynchonousFile = (function() { var cache = [], // 儲存本次需要同步檔案的id timer; // 定時器 return function(id) { cache.push(id); if(timer) { // 不要覆蓋已經啟動的定時 return; } timer = setTimeout(function(){ synchronousFile(cache.join(",")); clearTimeout(timer); timer = null; cache.length = 0; // 清空緩衝 }, 2000); }})();var checkboxs = document.getElementsByTagName("input");for(var i = 0, c; c = checkboxs[i]; i++) { c.onclick = function() { if(this.checked === true) { proxySynchonousFile(this.id); } }}
四、緩衝代理–計算乘積(序列一模一樣)
var mult = function() { var result = 1; for(var i = 0, l = arguments.length; i < l; i++) { result= result * arguments[i]; } return result;};var proxyMult = (function() { var cache = {}; // {"1,2,3": 6} return function() { var args = Array.prototype.join.call(arguments, ","); if(args in cache) { return cache[args]; } return cache[args] = mult.apply(this, arguments); }})();console.log(proxyMult(1, 2, 3));// 改造:var proxyFactory = 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); } };console.log(proxyFactory(mult)(1, 2, 3));
希望本文所述對大家學習javascript程式設計有所協助。
您可能感興趣的文章:
- JavaScript設計模式之代理模式介紹
- 深入理解JavaScript系列(31):設計模式之代理模式詳解
- 學習JavaScript設計模式(代理模式)