1. 程式人生 > >es6-Proxy、Reflect

es6-Proxy、Reflect

Proxy

攔截操作、修改物件的預設行為。

// target引數表示要攔截的目標物件,handler引數處理攔截行為。
var proxy = new Proxy(target,handler);
var user = {
	name:'admin',
	age:'22'
}
1.get()
var proxy = new Proxy(user,{
	get(target,property) {
		if(property in target){
			return target[property];
		}else{
			throw new ReferenceError("Property \ "+property+" \" does not exist");
		}
	}
});
proxy.name;              //"admin"
proxy.pass;               // 丟擲錯誤
// 如果沒有攔截操作,訪問不存在的屬性會返回undefined。
// 實現陣列讀取負數索引
function createArray(...item){
	let handler = {
		get(target,prop,receiver) {
			let index = Number(prop);
			if(index < 0){
				prop = String(target.length+index);
			}
			return Reflect.get(target,prop,receiver);
		}
	}
	let target = [];
	target.push(...item);
	return new Proxy(target,handler);
}
let arr = createArray(3,4,5);
arr[2];           //5
arr[-1];          //5
2.set()
利用set方法,可以資料繫結,即物件發生變化時,會自動更新DOM。
let proxy = new Proxy(user,{
	set(target,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");
			}
		}
		target[prop] = value;
	}
});
proxy.age;           //22
proxy.age = "hello";           //拋處一個錯誤,‘The age is not an integer’
proxy.age = 300;              //拋處一個錯誤,‘The age seems invalid’
3.可攔截操作過濾掉私有屬性,以‘_’為字首的屬性。
> has()/攔截 in 操作符
var handler = {
	has(target,key) {
		if(key[0] === '_'){
			return false;
		}
		return key in target;
	}
}
var target = {_name:'admin',name:'xiao li'};
var proxy = new Proxy(target,handler);
'_name' in proxy;            //false;
'_name' in target;             //true
> enumerate()/攔截for...in迴圈                                 **未支援
var handler = {
	enumerate(target) {
		return Object.keys(target).filter(key=>key[0]!=='_')[Symbol.iterator]();
	}
}
var target = {name:'admin',_name:'System',_age:'34'};
var proxy = new Proxy(target,handler);
for(let key in proxy){
	console.log(key);
}             //name
> getPrototypeOf()
攔截以下操作:
	Object.getPrototypeOf();
	Object.prototype.__proto__;
	Object.prototype.isPrototypeOf();
	Object.getPrototypeOf();
	Reflect.getPrototypeOf();
	instanceOf運算子

Proxy.revocable() 返回一個可取消的Proxy例項。

let target = {};
let handler = {};
let {proxy,revoke} = Proxy.revocable(target,handler);
proxy.name = "admin";
proxy.name;         //"admin"

revoke();
proxy.name;        // 拋處錯誤,‘has been revoked’

Proxy是針對Proxy例項進行操作的,訪問原物件不會攔截操作。 Proxy支援的攔截操作的方法和Reflect物件的方法對應。

Reflect

為操作物件提供的新API。 特點:

1.將Object物件上屬於語言層面的方法放到Reflect物件上。 2.修改了Object物件某些方法的返回結果。 3.讓Object一些命令式的操作都變成函式行為, 4.Reflect物件的方法與Proxy物件的方法一一對應。

Reflect物件的方法。

1、
var obj = {
	name:'hello'
}
Reflect.getOwnPropertyDescriptor(obj,"name");
/**
	{	configurable:true
		enumerable:true
		value:"hello"
		writable:true
	}
**/
Reflect.defineProperty(obj,"name",{
	enumerable:false
});                           //true
Reflect.getOwnPropertyNames	(obj);             //未支援,
Object.getOwnPropertyNames(obj);              //"name"
2、某些對應Object的方法,替代
Reflect.has(obj,name);         === name in obj
Reflect.deleteProperty(obj,name);          === delete obj[name]
Reflect.construct(target,args);          === new target(...args);
物件 方法 引數 描述
Reflect .getOwnPropertyDescriptor target,name 獲取目標物件的描述屬性
.defineProperty target,name,desc 定義屬性的描述物件
.getOwnPropertyNames target **未支援
.getPrototypeOf target 獲取物件的原型物件
.setPrototypeOf target,prototype
.deleteProperty target,name 刪除物件中的屬性
.enumerate target **未支援
.freeze target 凍結物件,防止修改
.seal target 密封物件,防止刪除
.preventExtensions target 防止物件的擴充套件
.isFrozen target
.isSealed target
.isExtensible target
.isPrototypeOf target 檢測目標物件是存在於另一個物件的原型鏈上
obj .propertyIsEnumerable name 該屬性是否可列舉
.has target,name 是否擁有該屬性,返回Boolean
.hasOwn target,name **未支援
obj .hasOwnProperty name 物件是否包含該屬性
.keys target **未支援
.ownKeys target 返回物件的屬性名
.get target,name,receiver
.set target,name,value,receiver
.apply target,thisArg,args
.construct target,args
.valueOf target 返回物件的原始屬性
.toString