proxy与reflect

205 阅读3分钟

一、proxy

Proxy 对象用于创建一个对象的代理,用代理对象覆盖目标对象,使目标对象对用户不可见,从而实现被代理对象基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

const target = new Proxy(target, handler)

target:被代理的对象

handler :一个通常以方法作为属性的对象,对代理对象的执行某些操作时,会触发对应的方法。比如:

1、赋值:触发set;

2、取值:get;

3、in操作符:触发has;

案例1:

var target = {
		name: '七鸽',
		phone: 13838480813
	},
	handle = {
		get(target, key,proxy) {
			console.log(arguments.length)//3
			return obj[key]
		},
		set(target, key, value,proxy) {
			console.log(arguments.length)//4
			obj[key] = value
		}
	};
proxy = new Proxy(target, handle);
 console.log(proxy.name)//七鸽
proxy.sex = 'man'
console.log(proxy.sex);//man

1-1、当访问时会触发handel对象的get的方法,传了3个参数,

参数1是目标象target;

参数2是访问属性key;

参数3是代理对象proxy;

get方法内部的arguments如下图:

image.png 1-2、当访问时会触发handel对象的set的方法,传了4个参数,

参数1是目标象target;

参数2是设置的属性名key;

参数3是设置的属性值value;

参数4是代理对象proxy;

set方法内部的arguments如下图:

image.png

1-3、假如不通过代理对象,直接操作目标对象,handle对象的方法就不会被触发。代码如下:

var target = {
		name: '七鸽',
		phone: 13838480813
	},
	handle = {
		get(obj, key) {
			console.log(arguments);//不打印
			return obj[key]
		},
		set(obj, key, value) {
			console.log(arguments);//不打印
			obj[key] = value
		}
	};
proxy = new Proxy(target, handle);
target.name='舞载';
target.sex = 'man'
console.log(proxy.sex)//man

通过以上代码证明:handled对象中的get、 set方法并不执行,。但是通过代理对象也可以访问sex属性,是因为proxy对象中保存了目标对象的引用。handled对象中的get set方法不执行,也就意味着起不了拦截的作用,如果要保证100%拦截目标对象的操作,必须让目标对象指向代理对象。代码如下:

function observer(target) {
	return new Proxy(target, {
		get(obj, key, proxy) {
			console.log(arguments.length);//3
			return obj[key];
		},
		set(obj, key, value, proxy) {
			console.log(arguments.length);//4
			obj[key] = value;
		}
	});
}
var target = {
	name: '七鸽',
	phone: 13838480813,
};
target=observer(target);
target.sex = 'man';
console.log(target.sex) //man

二、reflect

reflect是一个内置对象,它并不是一个函数,提供一些类似Object静态方法的静态方法。

image.png

var target = {
	name: '七鸽',
	phone: 13838480813,
};
console.log(Reflect.defineProperty(target, 'sex', { value: 'man' }));//true
console.log(Reflect.set(target, 'age',18));//true
console.log(Reflect.get(target, 'age'));//18
console.log(Reflect.getOwnPropertyDescriptor(target, 'age'));
console.log(Reflect.getPrototypeOf(target));
console.log(target);
console.log(Reflect.has(target, 'name'));//true
console.log(Reflect.ownKeys(target));// ["name", "phone", "sex", "age"]

image.png

2-1、给对象添加一个属性的方法PK:

var target = {
	name: '七鸽',
	phone: 13838480813,
};
target.hobby='fishing';
target['id']='5454543535';
console.log(Object.defineProperty(target, 'sex', { value: 'man' }));//返回原对象
console.log(Reflect.defineProperty(target, 'job', { value: 'study' }));//true
console.log(Reflect.set(target, 'age',18));//true
console.log(Reflect.get(target, 'hobby'));//18
console.log(target);

1、Object.defineProperty和Reflect.definePropert的异同:返回值不同,设置的属性配置项都为false;

2、Reflect.defineProperty和Reflect.set的异同:返回值都是boolean值,Reflect.set添加的属性配置项都为true。

案例:Proxy与Reflect的结合使用

function observer(target) {
	return new Proxy(target, {
		get(obj, key, proxy) {
			console.log(arguments.length); //3
			// return obj[key];
			return Reflect.get(obj,key)
		},
		set(obj, key, value, proxy) {
			console.log(arguments.length); //4
			// obj[key] = value;
			console.log(Reflect.set(...arguments));//true
		}
	});
}
target=observer(target);
target.sex = 'man';
console.log(target.sex) //舞载