Reflect
Reflect是一个内置的JS对象,它提供了一系列方法,可以让开发者通过调用这些方法,访问一些JS底层的功能
Reflect API
-
Reflect.set(target, propertyKey, value)
设置target对象的属性propertyKey的值为value
-
Reflect.get(target,propertyKey)
读取target对象的属性propertyKey
-
Reflect.apply(target, thisArgument, argumentsArr)
调用一个函数target,并绑定this和参数列表
-
Reflect.deleteProperty(target, propertyKey)
删除target对象的属性propertyKey
-
Reflect.defineProperty(target, propertyKey, attributes)
类似于Object.defineProperty(),不过Object.defineProperty()若属性描述符配置不当会报错(如同时配置getter和value),而Reflect.defineProperty()若配置不当不会报错,而只是会返回false
-
Reflect.construct(target, argumentsArr)
利用构造函数target创建一个对象
-
Reflect.has(target, propertyKey)
判断target对象中是否有属性propertyKey
其它Reflect API:developer.mozilla.org/zh-CN/docs/…
Proxy
proxy对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性访问、赋值、枚举、函数调用等)
创建Proxy
const proxy = new Proxy(target, handler);
target为接受代理的对象,handler也是一个对象,其中可以配置许多动作捕获的方法,即捕获器
为target添加了proxy后,就不应该再直接操作target,而是需要通过操作proxy来间接操作target
handler中的动作捕获器
Reflect中有的API,handler中都可以有,且名称和参数列表也相同
handler中的捕获器函数,它们的第一个参数target就是接受代理的对象target
-
has(target, propertyKey)
in操作符的动作捕获器
当对proxy使用in操作符时,会调用该捕获器,且该函数的返回值会作为其in表达式的返回值
const target = { a: 1 }; const proxy = new Proxy(target, { has(target, propertyKey){ console.log(target, propertyKey); return "a" in target; } }); console.log("a" in proxy); // 将调用handler的has捕获器 // { a: 1 } "a" // true -
get(target, propertyKey)
属性读取操作的动作捕获器
当读取proxy的属性时,会调用该捕获器,且该函数的返回值会作为获取到的值
-
set(target, propertyKey, value)
属性设置操作的动作捕获器
当设置proxy的属性时,会调用该捕获器
-
deleteProperty(target, propertyKey)
delete操作符的动作捕获器
当删除proxy的属性时,会调用该捕获器
-
apply(target, thisArgument, argumentsArr)
函数调用操作的动作捕获器
当调用proxy时,会调用该捕获器,且该函数的返回值会作为调用proxy的值
function target(){ console.log("target fn"); } const proxy = new Proxy(target, { apply(target, thisArgument, argumentsArr){ console.log("apply"); target(); } }); proxy(); // "apply" // "target fn" -
construct(target, argumentsArr)
构造函数调用操作的动作捕获器
当使用new关键字调用proxy时,会调用该捕获器,且该函数的返回值会作为new proxy()所创建的对象
注意:handler中所有的捕获器都是可选的,如果没有定义某个捕或器,那么在对proxy进行相应操作时,会自动转换为对target的对应操作
观察者模式
可以通过观察目标对象的属性变化,来进行一些其他的操作
使用Object.defineProperty实现观察者模式
function observer(target) {
for (const prop in target) {
let val = target[prop];
if(typeof target[prop] === "object" && typeof target[prop] !== "null"){
observer(target[prop]);
}
Object.defineProperty(target, prop, {
get() {
// 这里可以进行一些其它操作
return val;
},
set(value) {
// 这里可以进行一些其它操作
val = value;
}
});
}
}
缺陷:
- 需要深度遍历target,会造成效率上的损失
- 对于设置了观察者后再往target中新增的属性,将不具有被观察的效果
- 无法观察到除设置和获取外的其他操作
使用Proxy实现观察者模式
function observer(target) {
const proxy = new Proxy(target, {
get(target,propertyKey){
// 这里可以进行一些其它操作
return Reflect.get(target, propertyKey);
},
set(target, propertyKey, value){
// 这里可以进行一些其它操作
Reflect.set(target, propertyKey, value);
},
has(target, propertyKey){
// 这里可以进行一些其它操作
return Reflect.has(target, propertyKey);
},
delete(target, propertyKey){
// 这里可以进行一些其它操作
Reflect.delete(target, propertyKey);
},
...
});
return proxy;
}