前言
这两个对象都是ES6新增的对象,之前零零散散用过一些,今天做下简单的总结。
Proxy
概述
个人理解是对目标的对象做一层拦截操作,凡事要操作目标对象(读、写等)都需要经过这层代理进行拦截,拦截过后才能访问到目标对象。Vue3的数据绑定也是使用Proxy实现的(区别于Vue2的Object.defineProperty)
基本语法
var proxy = new Proxy(target, handler);
其中 target 表示要拦截的目标对象,handler是拦截操作的定义,也是一个Javascript对象。
handler 列表
- get(target, propKey, receiver) :拦截对象属性的读取,比如`proxy.foo`和`proxy['foo']`。
- set(target, propKey, value, receiver) :拦截对象属性的设置,比如`proxy.foo = v`或`proxy['foo'] = v`,返回一个布尔值。
- has(target, propKey) :拦截`propKey in proxy`的操作,返回一个布尔值。
- deleteProperty(target, propKey) :拦截`delete proxy[propKey]`的操作,返回一个布尔值。
- ownKeys(target) :拦截`Object.getOwnPropertyNames(proxy)`、`Object.getOwnPropertySymbols(proxy)`、`Object.keys(proxy)`、`for...in`循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而`Object.keys()`的返回结果仅包括目标对象自身的可遍历属性。
- getOwnPropertyDescriptor(target, propKey) :拦截`Object.getOwnPropertyDescriptor(proxy, propKey)`,返回属性的描述对象。
- defineProperty(target, propKey, propDesc) :拦截`Object.defineProperty(proxy, propKey, propDesc)`、`Object.defineProperties(proxy, propDescs)`,返回一个布尔值。
- preventExtensions(target) :拦截`Object.preventExtensions(proxy)`,返回一个布尔值。
- getPrototypeOf(target) :拦截`Object.getPrototypeOf(proxy)`,返回一个对象。
- isExtensible(target) :拦截`Object.isExtensible(proxy)`,返回一个布尔值。
- setPrototypeOf(target, proto) :拦截`Object.setPrototypeOf(proxy, proto)`,返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
- apply(target, object, args) :拦截 Proxy 实例作为函数调用的操作,比如`proxy(...args)`、`proxy.call(object, ...args)`、`proxy.apply(...)`。
- construct(target, args) :拦截 Proxy 实例作为构造函数调用的操作,比如`new proxy(...args)`。
示例
const validator = {
set: function(obj, 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');
}
}
// The default behavior to store the value
obj[prop] = value;
// 表示成功
return true;
}
};
const person = new Proxy({}, validator);
person.age = 100;
console.log(person.age);
// 100
person.age = 'young';
// 抛出异常: Uncaught TypeError: The age is not an integer
person.age = 300;
// 抛出异常: Uncaught RangeError: The age seems invalid
好处
第一次使用这个对象是由于一次前端bug的修复:
之前遇到一个奇怪的问题,在用户做了某些操作之后,一个全局对象被修改了,导致了一些奇奇怪怪的问题。
所以使用了Proxy进行对这个全局对象进行拦截,当set的拦截器中打个断点,通过看 Call Stack 找到了修改对象的代码位置。
后面也陆陆续续用这个方法定位过问题,自认为还是挺好用的。(但是对 Proxy的使用也只是停留在这么基本的使用,如果后续有更好的使用姿势,继续更新在这里)。
兼容性
Reflect
概述
将部分 Object 上的方法,放到 Reflect上做静态方法使用。(说实话,get不到 Reflect的用处有多大,至少跟ES6其他语法比较,可能只是想规范下 Object上的方法。)
基本语法
Relect.xxx(target, ...args)
静态方法列表
- Reflect.apply(target, thisArg, args)
- Reflect.construct(target, args)
- Reflect.get(target, name, receiver)
- Reflect.set(target, name, value, receiver)
- Reflect.defineProperty(target, name, desc)
- Reflect.deleteProperty(target, name)
- Reflect.has(target, name)
- Reflect.ownKeys(target)
- Reflect.isExtensible(target)
- Reflect.preventExtensions(target)
- Reflect.getOwnPropertyDescriptor(target, name)
- Reflect.getPrototypeOf(target)
- Reflect.setPrototypeOf(target, prototype)
大部分方法都能在 Object上找到,也和Proxy拦截器一一对应。
示例
const duck = {
name: 'Maurice',
color: 'white',
greeting: function() {
console.log(`Quaaaack! My name is ${this.name}`);
}
}
Reflect.get(duck, 'name')
// Maurice
Reflect.has(duck, 'color');
// true
Reflect.has(duck, 'haircut');
// false
好处
待发掘。。。。。。