在實際開發中常常會遇到js拋出的錯誤,可是咱們有沒有想過本身去接管js異常驗證,根據本身的需求拋出異常呢?本來也許不行,可是在es6出來後就能夠作到了es6
什麼是‘代理’ 呢?代理:就是調用new 建立一個和目標(traget)對象一直的虛擬化對象,然該代理中就能夠攔截JavaScript引擎內部目標的底層對象的操做;這些底層操做被攔截後會觸發響應特定操做的陷阱函數
來看個簡單的案例api
let tartget = {}; let proxy = new Proxy(target,{}); proxy.name = 'proxy'; console.log(proxy.name); // proxy console.log(tartget .name); // proxy tartget .name = 'tartget'; console.log(proxy.name); // target console.log(tartget .name); // target
如案例
如proxy.name = 'proxy';
將proxy賦值給proxy.name時,代理就會將該操做轉發給目標,執行name屬性的建立;然而他只是作轉發而不會存儲該屬性;
so他們之間存在一個相互引用;tartget .name設置一個新值後,proxy.name值也改變了;數組
那反射又是什麼呢?反射:它提供了一個Reflect對象API;該對像中的方法默認特性與底層的操做對應;而每個代理陷阱會對應一個命名和參數都相同的Reflect方法(其實就是每一個代理陷阱都會對應一個Reflect api接口供覆寫JavaScript底層操做)app
映射關係以下表:函數
代理陷阱 | 覆寫的特性 | 默認特性 |
---|---|---|
get | 讀寫一個屬性值 | Reflect.get() |
set | 寫入一個屬性 | Reflect.set() |
has | in操做 | Reflect.has() |
deleteProperty | delete操做符 | Reflect.deleteProperty() |
getAPrototypeof | Object.getAPrototypeof () | Reflect.getAPrototypeof () |
setAPrototypeof | Object.setAPrototypeof () | Reflect.setAPrototypeof () |
isExtensible | Object.isExtensible() | Reflect.isExtensible() |
preventExtensions | Object.preventExtensions() | Reflect.preventExtensions() |
getOwnPropertyDescriptor | Object.getOwnPropertyDescriptor() | Reflect.getOwnPropertyDescriptor() |
defineaProperty | Object.defineaProperty() | Reflect.defineaProperty() |
ownKeys | Object.keys() 、 Object.getOwnPropertyNames()和 Object.getOwnPropertySysmbols() | Reflect.ownKeys() |
apply | 調用一個函數 | Reflect.apply() |
construct | 用new調用一個函數 | Reflect.construct() |
接下來使用set陷阱來驗證一下對象屬性賦值操做(如爲對象新增屬性,要求必須賦值爲int)測試
let target = { name :'target' }; let proxy = new Proxy(target,{ set(trapTarget,key,value,receiver){ //忽略不但願受到影響的已有屬性 if(!trapTarget.hasOwnProperty(key)){ if(isNaN(key)){ throw new TypeError("屬性必須是數字喲,親!"); } } // 添加屬性 return Reflect.set(trapTarget,key,value,receiver); } }); // 添加一個新屬性 proxy.count = 1; console.log(proxy.count); // 1 console.log(proxy.count); // 1 // 因爲目標已有name屬性,so 如上第一個if不成立(賦值成功) proxy.name= "proxy"; console.log(proxy.name); // proxy console.log(proxy.name); // proxy // 新建一個屬性同時賦值一個非int 值,第一個if成立,第二個if驗證isNaN(key) = true 即拋出異常 proxy.anotherName = "proxy";
案例中set(trapTarget,key,value,receiver)
這個set陷阱默認接收 四個參數this
如spa
let target = {}; console.log(target.name); // undefined
在JavaScript中調用一個對象不存在的屬性不會報錯,反而使用undefined代替被讀取屬性的值代理
而喝多時候會帶來意想不到的bug,如今咱們可使用get陷阱來驗證該問題
依然看這個案例code
let proxy = new Proxy(target,{ get(trapTarget,key,receiver){ //忽略不但願受到影響的已有屬性 if(!(key in receiver)){ throw new TypeError("sorry 親! 你找的 "+key+" 屬性不存在。!") } // 添加屬性 return Reflect.get(trapTarget,key,receiver); } }); // 添加一個屬性, proxy.name= "proxy"; console.log(proxy.name); // proxy // 讀取一個不存在的屬性 直接會拋出異常 console.log(proxy.nme);
如上使用in操做判斷receiver中是否存在被讀取的屬性;若是沒有拋出異常
其中get(trapTarget,key,receiver)
參數
使用這個兩個陷阱來驗證函數調用時的參數的正確性
以下案例
// 參數求和 function sum (...values){ return values.reduce((previous,current) => prvious + current, 0); } let sumProxy = new Proxy(sum,{ apply:function(trapTarget,thisArg,argumentList){ argumentList.forEach(arg => { if(typeof arg !== "number"){ throw new TypeError("全部參數必須是數字,親!"); } }); return Reflect.apply(trapTarget,thisArg,argumentList); }, // 防止使用new 關鍵字調用 construct:function(trapTarget,argumentList){ throw new TypeError("親,你不能這麼幹,該函數不能經過new調用。"); } }); // 測試哈 console.log(sumProxy(1,2,3,4)); // 10 // 傳入一個非數字的屬性值試試 【直接拋出異常】 console.log(sumProxy(1,「2」,3,4)); // 10 // 一樣使用new調用 【直接拋出異常】 let result = new sumProxy();
apply陷阱和Reflect.apply()都接受一樣的參數
當使用new調用函數時 會觸發construct陷阱,接收的參數爲
其中Reflect.construct()第三個參數是newTarget 這是一個可選參數。用於指定該函數內部
new.target的值
看到這裏有沒有感受這個對於js項目代碼檢測仍是蠻有用處的呢。 ok先到這裏,時間不早了改且休息了;改天繼續…