代理模式是爲一個對象提供一個代用品或佔位符,以便控制對它的訪問。es6
按職責來劃分的話,分爲如下8種代理:數組
一、緩存代理緩存
二、虛擬代理app
三、寫時複製Copy-on-Write 代理函數
四、保護(Protect or Access)代理ui
五、Cache代理this
六、防火牆(Firewall)代理spa
七、同步化(Synchronization)代理prototype
八、智能引用(Smart Reference)代理設計
在js中經常使用到的是緩存代理和虛擬代理
// 不使用代理的預加載圖片函數以下
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 = "loading.gif";
img.src = src;
}
}
})();
// 調用方式
myImage.setSrc("pic.png");
複製代碼
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("loading.gif");
img.src = src;
}
}
})();
// 調用方式
ProxyImage.setSrc("pic.png");
複製代碼
一、建立img標籤
二、插入img標籤
三、建立img對象
四、書寫onloading方法
五、返回設置圖片對象。
缺點:
一、代碼耦合度比較大,一個函數內負責作了幾件事情。未知足面向對象設計原則中單一職責原則;
二、當某個時候不須要圖片預加載的時候,須要從myImage 函數內把代碼刪掉,這樣代碼耦合性過高。
一、myImage中建立img標籤
二、myImage中插入img標籤
三、myImage中返回設置imgNode的src方法
四、ProxyImage中建立img對象
五、ProxyImage中書寫onload方法
六、ProxyImage中返回設置圖片的方法。
優勢:
一、myImage 函數只負責作一件事。建立img元素加入到頁面中,其中的加載loading圖片交給代理函數ProxyImage 去作。
二、加載成功之後,代理函數ProxyImage 會通知及執行myImage 函數的方法。
三、當之後不須要代理對象的話,咱們直接能夠調用本體對象的方法便可
緩存代理,就是將前面使用的值緩存下來,後續還有使用的話,就直接拿出來用。
var add = function(){
var sum = 0
for(var i = 0, l = arguments.length; i < l; i++){
sum += arguments[i]
}
return sum
}
var proxyAdd = (function(){
var cache = {} //緩存運算結果的緩存對象
return function(){
var args = Array.prototype.join.call(arguments)
if(cache.hasOwnProperty(args)){//等價 args in cache
console.log('使用緩存結果')
return cache[args]//直接使用緩存對象的「值」
}
console.log('計算結果')
return cache[args] = add.apply(this,arguments)//使用本體函數計算結果並加入緩存
console.log(cache);
}
})()
console.log(proxyAdd(1,2,3,4,5))
console.log(proxyAdd(1,2,3,4,5))
console.log(proxyAdd(1,2,3,4,5))
// 輸出結果
計算結果
15
使用緩存結果
15
使用緩存結果
15
複製代碼
二者的職責劃分:add函數提供計算功能。proxyAdd提供訪問add函數的功能和緩存功能。
const target = {}, handler = {}
const proxy = new Proxy(target, handler)
複製代碼
target是目標對象,handler是處理函數。
var handler = {
get: function() {},
set: function() {},
apply: function() {},
construct: function() {},
}
複製代碼
參數:目標對象、屬性名、proxy實例自己
例子:
var person = {
name: "張三"
};
var proxy = new Proxy(person, {
get: function(target, property) {
if (property in target) {
return target[property];
} else {
throw new ReferenceError("Property \"" + property + "\" does not exist.");
}
}
});
proxy.name // "張三"
proxy.age // 拋出一個錯誤
複製代碼
參數:目標對象、屬性名、屬性值、proxy實例自己
例子:
let validator = {
set: function(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('The age is not an integer');
}
if (value > 200) {
throw new RangeError('The age seems invalid');
}
}
// 對於知足條件的 age 屬性以及其餘屬性,直接保存
obj[prop] = value;
}
};
let a = {}
let person = new Proxy(a, validator);
person.age = 100;
a.age // 100
person.age = 'young' // 報錯
person.age = 300 // 報錯
複製代碼
參數:目標對象,目標對象的上下文,參數組 例子:
var target = function () { return 'I am the target'; };
var handler = {
apply: function () {
return 'I am the proxy';
}
};
var p = new Proxy(target, handler);
p() // I am the proxy
複製代碼
當調用p函數時,就會被proxy
攔截,返回I am the proxy
。
construct
方法用於攔截new
指令。
參數:目標對象、構造函數的參數對象 例子:
var P = new Proxy(function () {}, {
construct: function(target, args) {
console.log('called: ' + args.join(', '));
return { value: args[0] * 10 };
}
});
const p = new P(1);
// "called: 1"
p.value
// 10
複製代碼
let myImage = (function(){
var imgNode = document.createElement("img");
document.body.appendChild(imgNode);
return {
setSrc: function(src) {
imgNode.src = src;
}
}
})();
let myImageProxy = new Proxy(myImage, {
apply(target, ctx, arguments) {
let img = new Image
img.onload = function(){
// 圖片加載完成,正式加載圖片
target.call(ctx, ...arguments)
}
// 圖片未被載入時,加載一張提示圖片
target.call(ctx, 'file://c:/loading.png')
img.src = arguments[0]
}
})
// 調用
let myImg = new myImageProxy(document)
myImg.setSrc('http://images/qq.jpg')
複製代碼