Reflect 的定义
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与 proxy handler 的方法相同。Reflect 不是一个函数对象,因此它是不可构造的。Reflect 的所有属性和方法都是静态的。
静态方法
-
Reflect.apply(target, thisArgument, argumentsList)
对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和 Function.prototype.apply() 功能类似。 -
Reflect.construct(target, argumentsList[, newTarget])
对构造函数进行 new操作,相当于执行 new target(…args) -
Reflect.defineProperty(target, propertyKey, attributes)
和Object.defineProperty() 类似。如果设置成功就会返回 true -
Reflect.deleteProperty(target, propertyKey)
作为函数的delete操作符,相当于执行delete target[name] -
Reflect.get(target, propertyKey[, receiver])
获取对象身上某个属性的值,类似于target[name] -
Reflect.getOwnPropertyDescriptor(target, propertyKey)
类似于Object.getOwnPropertyDescriptor()。如果对象中存在该属性,则返回对应的属性描述符,否则返回undefined。 -
Reflect.getPrototypeOf(target)
类似于 Object.getPrototypeOf()。 -
Reflect.has(target, propertyKey)
判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。 -
Reflect.isExtensible(target)
类似于 Object.isExtensible(). -
Reflect.ownKeys(target)
返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys(),但不会受enumerable 影响). -
Reflect.preventExtensions(target)
类似于Object.preventExtensions()。返回一个Boolean。 -
Reflect.set(target, propertyKey, value[, receiver])
将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true。 -
Reflect.setPrototypeOf(target, prototype)
设置对象原型的函数。返回一个Boolean,如果更新成功,则返回 true。
我们发现这13个静态方法,与proxy代理的handler中13个方法的方法名是完全一致的,其实这些方法就是proxy代理的那些方法内部的默认实现,你可能觉得这句话不是很好理解,我们这里来用代码说明一下。
let obj = {name: 'mike'};
let proxy = new Proxy(obj, {});
proxy.name // 'mike'
上面的代码中,我们并没有配置handler中的get方法,可是proxy.name却可以正常获取name的属性值,现在我们怀疑在没有配置相关handler处理方法的情况下,会有一个默认的处理方法
下面我们再改造一下上面代码,添加一个get处理方法
let obj = {name: 'mike'};
let proxy = new Proxy(obj, {
get(target, key){
console.log('proxy get');
}
});
proxy.name
// 'proxy get'
我们发现,如果我们配置一个get的处理方法,但是我们并没有添加相应的返回语句的话,这里的proxy.name当然会拿不到值
那么结合Reflect我们来试试吧
let obj = {name: 'mike'};
let proxy = new Proxy(obj, {
get(target, key){
console.log('proxy get');
return Reflect.get(target, key);
}
});
proxy.name
//proxy get
//'mike'
这下我们确定了,Reflect的静态方法就是Proxy处理对象那些方法内部的默认实现.
而且这种写法非常简洁漂亮,毕竟在ES5就有减少魔法、让代码更加纯粹的理念.
这种理念很大程度上是受到函数式编程的影响,ES6进一步贯彻了这种理念,它认为,对属性内存的控制、原型链的修改、函数的调用等等,这些都属于底层实现,属于一种魔法,因此,需要将它们提取出来,形成一个正常的API,并高度聚合到某个对象中,于是,就造就了Reflect对象
因此,你可以看到Reflect对象中有很多的API都可以使用过去的某种语法或其他API实现。
所以,我们可以使用Reflect的静态方法来代替对象的操作方式,我们看看下面
let obj = {name: 'mike'};
- 获取对象上的属性值
Reflect.get(obj, 'name'); //'mike'
- 给属性添加属性
Reflect.set(obj, 'age', 18); // true
obj // {name: 'mike', age: 18}
- 判断对象是否有某个属性
Reflect.has(obj, 'name') // true
- 删除对象的属性
Reflect.deleteProperty(obj, 'name') // true
obj //{age: 18}
通过定义属性的方式给对象添加属性
Reflect.defineProperty(obj, 'sex', {value: 'man'}); // true
obj // {age: 18, sex: 'man'}
- 获取对象上的所有key(用Reflect的ownKeys获取不会受enumerable 影响)
Reflect.defineProperty(obj, 'sex', {value: 'man'}); // true
obj // {age: 18, sex: 'man'}
Reflect.ownKeys(obj) // ['age', 'sex']
Object.keys(obj) //['age']
for(let key in obj) {console.log(key)}
//age
举例就先到这里,不常用的这里不做赘述了,有需要的小伙伴可以自行体验哈~
所以,Reflect在配合proxy一起使用时,我们在自定义的get、set这样的处理方法中,更为标准的做法是,先去实现自己所需要的监视逻辑,最后再去返回通过Reflect中对应的方法的一个调用结果。
完结!