深入理解ES6之——代理和反射(proxy)
阿新 • • 發佈:2019-08-15
通過呼叫new proxy()你可以建立一個代理來替代另一個物件(被稱為目標),這個代理對目標物件進行了虛擬,因此該代理與該目標物件表面上可以被當做同一個物件來對待。
建立一個簡單的代理
當你使用Proxy構造器來建立一個代理時,需要傳遞兩個引數:目標物件以及一個處理器,後者是定義了一個或多個陷阱函式的物件。如果未提供陷阱函式,代理會對所有操作採取預設行為。
使用set陷阱函式驗證屬性值
let target = {}; var proxy = new Proxy(target, { set(trapTarget, key, value, receiver) { if (!trapTarget.hasOwnProperty(key)) { if (isNaN(value)) { throw new Error('Proxy must be a number'); } } return Reflect.set(trapTarget, key, value, receiver); } }) proxy.count = 1; console.log(proxy.count); console.log(target.count); try { proxy.anthorName = 'cc'; } catch (err) { console.log(err.message); }
使用上述方法可以對新增給物件的屬性值進行驗證,如果值為非數字,就會丟擲錯誤。
使用get陷阱函式進行物件外形驗證
在js中,如果讀取一個物件中不存在的屬性時,會顯示undefined,這對於排查問題很不利。使用代理進行物件外形驗證就可以幫你從這個錯誤中拯救出來。
let proxy = new Proxy({}, { get(trapTarget, key, receiver) { if (!(key in receiver)) { throw new Error(`property ${key} not exist`); } return Reflect.get(trapTarget, key, receiver); } }) proxy.name = 'cc'; try { console.log(proxy.age); } catch (error) { console.log(error.message); } //輸出結果 property age not exist
上述程式碼對列印的物件屬性進行驗證,如果不存在則丟擲一個錯誤。今日頭條的一個面試題
使用has陷阱函式隱藏屬性
in運算子用於判斷指定物件中是否存在某個屬性,如果物件的屬性名與指定的字串或符號值相匹配,那麼in運算子應當返回true,無論該屬性是物件自身的屬性還是原型的屬性。代理允許你使用has陷阱函式來解決這個問題
has陷阱函式會在使用in運算子的情況下被呼叫,並且會被傳入兩個引數:
- trapTarget:需要讀取屬性的物件(即代理的目標物件)
- key:需要檢查的屬性的鍵(字串型別或符號型別)Reflect.has()方法接收與之相同的引數並向in運算子返回預設相應結果
let target = { name: 'cc', age: 26, sex: 'man' } let proxy = new Proxy(target, { has(trapTarget, key) { if (trapTarget.hasOwnProperty(key)) { return Reflect.has(trapTarget, key); } else { return false; } } }) console.log('toString' in proxy); console.log('name' in proxy); console.log('age' in proxy);
使用deleteProperty陷阱函式避免屬性被刪除
delete運算子能從指定物件上刪除一個屬性,在刪除成功時返回true,否則返回false
deleteProperty陷阱函式會在使用delete運算子去刪除物件屬性時被呼叫,並且會被傳入兩個引數:
- trapTarget:需要刪除屬性的物件
- key:需要刪除的屬性的鍵
Reflect.deleteProperty()方法也接受兩個引數,並提供了deleteProperty陷阱函式的預設實現。
let target = {
name: 'target',
value: 42
}
let proxy = new Proxy(target, {
deleteProperty(trapTarg, ke) {
if (ke === 'value') {
return false;
} else {
return Reflect.deleteProperty(trapTarg, ke);
}
}
})
let result = delete proxy.value;
let result1 = delete proxy.name;
console.log(result);
console.log(result1);