js代理(Proxy) 和 反射(Reflection)

在實際開發中常常會遇到js拋出的錯誤,可是咱們有沒有想過本身去接管js異常驗證,根據本身的需求拋出異常呢?本來也許不行,可是在es6出來後就能夠作到了es6

1、代理(Proxy)

什麼是‘代理’ 呢?代理:就是調用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值也改變了;數組

2、反射(Reflect)

那反射又是什麼呢?反射:它提供了一個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()

3、使用set陷阱驗證屬性

接下來使用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

  • trapTarget 用於接收屬性(代理的目標)的對象
  • key 要寫入的屬性鍵(字符串或Symbol類型)
  • value 被寫入的屬性的值
  • receiver 操做發生的對象(一般是代理)

4、使用get 陷阱驗證對象結構

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) 參數

  • trapTarget 被讀取屬性源對象(代理的目標)
  • key 要讀取的屬性鍵(字符串或Symbol類型)
  • receiver 操做發生的對象(一般是代理)

5、函數代理apply和construct陷阱

使用這個兩個陷阱來驗證函數調用時的參數的正確性
以下案例

// 參數求和
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()都接受一樣的參數

  • trapTarget 被執行的函數(代理的目標)
  • thisArg 函數被調用時內部的this的值
  • argumentList傳遞給函數的參數數組

當使用new調用函數時 會觸發construct陷阱,接收的參數爲

  • trapTarget 被執行的函數(代理的目標)
  • argumentList傳遞給函數的參數數組

其中Reflect.construct()第三個參數是newTarget 這是一個可選參數。用於指定該函數內部
new.target的值

看到這裏有沒有感受這個對於js項目代碼檢測仍是蠻有用處的呢。 ok先到這裏,時間不早了改且休息了;改天繼續…

相關文章
相關標籤/搜索