一、定義
當客戶不方便直接訪問一個物件或者不滿足需要的時候,提供一個物件來控制堆這個物件的訪問,
二、舉例
惰性單例模式的實作依靠快取代理
三、結構
代理模式需要一個本體物件和一個代理物件,在代理模式下,對于本體物件的特定的操作通過代理物件進行,如圖所示

這種模式的關鍵點在于:本體物件和代理物件介面的一致性,也就是說如果需要不通過代理進行操作,那么直接操作本體物件依然可以,
四、實作
代理模式分為很多類,其中經常用到的有保護代理、虛擬代理、快取代理,
1.保護代理
保護代理的作用是當對本體物件的屬性進行訪問和賦值時,代理物件可以對其進行攔截,
在ES6中,代理是一個已經被實作的知識點,如下:
var obj = { _name: "JYY", age: 29 }; var objProxy = new Proxy(obj, { get: function(target, key){ if(key === "_name") return undefined; return target[key]; }, set: function(target, key){ if(key === "_name") return; } }); objProxy._name; // undefined objProxy.age; // 29
上面的代碼中obj是本體物件,objProxy是代理物件,這個代理實作了禁止訪問和設定內部私有屬性的功能,在這段代碼中,我們使用代理物件對本體物件的get和set方法進行了代理,本體物件和代理物件都包含了這個set和get介面(obj物件本身內部實作了get和set),所以如果我們繞過代理物件直接訪問和賦值本體物件也是可以的:
var obj = { _name: "JYY", age: 29 }; console.log(obj._name); //JYY obj._name = "hah"; console.log(obj._name); // hah
保護代理的重點在于,代理物件保護外界對于本體物件的可訪問和可操作性,也就是說在保護代理中,代理物件是用于禁止外界對本體物件的操作,防止本體物件的屬性被外界進行操作
2.虛擬代理
虛擬代理在我理解,就是用戶認為已經執行了某個功能,事實上卻時使用代理物件進行占位,待觸發的時機到來,才會真正的執行本體物件的操作,也就是虛擬代理把一些開銷很大的物件,延遲到真正需要他的時候才采取創建,因此虛擬代理的使用伴隨的是性能的提升,
典型的虛擬代理的例子就是節流,如下所示:
var resizeProxy = function(fn){ let timer = null; return function(){ if(!timer){ timer = setTimeout(function(){ fn && fn(); timer = null; },1000) } } }; var resizeChange = function(){ console.log(1); }; window.onresize = resizeProxy(resizeChange);
這段代碼是經典的使用節流控制表單尺寸大小改變事件觸發的例子,作用就是讓resize事件的觸發不那么頻繁,自定義的控制觸發的頻率,這對于性能的提升很有幫助,
在這段代碼里面,resizeChange就是本體,resizeProxy就是代理,如果不使用代理直接將fn復制給window.onresize依舊是可用的,而使用代理的作用就是首先進行占位,開發中代理內部的代碼是不可見的(比如提供的是api),利用resizeProxy的不可見性,讓客戶認為已經呼叫了功能代碼,但是事實上是我們并未立即執行代碼,因為我們作為開發者知道立即執行會帶來性能的喪失,只有在合適的時機我們才會委托代理執行本地代碼,執行真正的業務代碼,
3.快取代理
快取代理在單例模式中就已出現,用于創建惰性代理模式,其原理就是在需要時創建物件,并將該物件保存在閉包中,這樣可以一次創建多次使用,
當然在惰性單例中使用是快取代理最簡單的實作方式,在實際開發中,我們可能會遇到這樣的場景,在tab中每個tab頁都包含多個圖表,因此在點擊tab的時候就需要獲取這個tab對應的圖表的資料,這些資料都需要從后端請求,比如以某個省的地市經濟統計情況為例,我們需要的頁面如下:
可見這樣的情況下,用戶很可能不斷地點擊tab切換城市,然后和其他城市進行對比,如果每次點擊都請求資料,帶給用戶的體驗會非常差,這樣的情況下,我們就可以做個全域的快取,當然你可以保存在組件的狀態中,除此之外快取代理也是個很棒的選擇,代碼如下:
// 請求資料 function requestData(regionName){ return new Promise(function(resolve, reject){ var rest = ajax({ type: "post", params: {regionName: regionName} }) resolve(rest); }) } // 初始化資料代理方法 var proxyInit = (function(){ var cache = {}; return async function(regionName){ if(cache[regionName]){ return cache[regionName]; }else{ return cache[regionName] = await requestData(regionName); } } }); proxyInit("石家莊");
五、總結
三種型別雖然均為代理模式,但是各自的目的并不相同,保護代理是為了阻止外部對內部物件的訪問或者是操作等;虛擬代理是為了提升性能,延遲本體執行,在合適的時機進行觸發,目的是減少本體的執行次數;快取代理同樣是為了提升性能,但是為了級訓記憶體的壓力,同樣的屬性,在記憶體中只保留一份,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/34174.html
標籤:JavaScript
