Reflect
之前的文章:
概述
Reflect 对象与Proxy 对象一样,也是 ES6 为了操作对象而提供的新 API.
切记,不可使用new操作符生成实例
特点
- 现阶段,Object上面内部语言方法(例 Object.defineProperty)会同步到Reflect上面一份。后续新增的则会放在Reflect对象上面。
- 修改某些Object的内部方法返回结果,使其变的合理。(以Object.defineProperty为例, 现在如果没有办法定义时,则会报错,放在Reflect上面,则会返回false)
- 使得Object的行为都变成函数形式(现如今,对于对象的操作,基本都是一行代码,对于解读,有点难。例如: delete obj.name .这种语句很容易让人忽略,并且如果没有注释,让人摸不住头脑)
- 配合Proxy,静态方法基本和Proxy的静态方法保持一致。
代码例子:(注意看注释)
// 1. new 操作符会报错,因为Reflect里面没有对应的构造函数
let reflect = new Reflect() // TypeError: Reflect is not a constructor
// 2. 对比方法,以Object.defineProperty为例。第一个结果是报错,第二个例子是false。
// 无法使用Object.defineProperty进行定义的属性有以下特点:
// 1. 内置对象的不可配置属性(例如:下例)
// 2. 特殊属性(例如:__proto__)
// 3. 全局对象的属性
// 4. 无法定义不可枚举的原型属性
// 5. 不可写和不可配置的属性等
try {
Object.defineProperty(Math, 'PI', {
value: 3, // 尝试将PI的值修改为3
writable: true,
enumerable: true,
configurable: true
});
} catch (e) {
console.error('Error:', e); // TypeError: Attempted to redefine non-configurable property 'PI'
}
try {
Reflect.defineProperty(Math, 'PI', {
value: 3, // 尝试将PI的值修改为3
writable: true,
enumerable: true,
configurable: true
});
} catch (e) {
console.error('Error:', e);
}
// 3. Object 的操作变成函数操作
let obj = {a: 1}
'a' in obj
Reflect.has(obj, 'a')
// 配合Proxy 进行使用
// 每一个 Proxy 对象的拦截操作( get 、 delete 、 has ),内部都调用对应的 Reflect 方法,保证原生行为能够正常执行
var loggedObj = new Proxy(obj, {
get(target, name) {
console.log('get', target, name);
return Reflect.get(target, name);
},
deleteProperty(target, name) {
console.log('delete' + name);
return Reflect.deleteProperty(target, name);
},
has(target, name) {
console.log('has' + name);
return Reflect.has(target, name);
}
});
静态方法
静态方法名称
- 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)
部分静态方法例子
Reflect.get(target, name, receiver)
- Reflect.get方法查找并返回 target 对象的 name 属性值,如果没有该属性,则返回 undefined 。
- 如果 name 属性部署了读取函数(getter),则读取函数的 this 绑定 receiver 。
- 如果第一个参数不是对象, Reflect.get 方法会报错。
// 说明1的例子如下:
var myObject = {
foo: 1,
bar: 2,
get baz() {
return this.foo + this.bar;
},
}
console.log(Reflect.get(myObject, 'foo')) // 1
console.log(Reflect.get(myObject, 'bar')) // 2
console.log(Reflect.get(myObject, 'baz')) // 3 没有传receiver,则this取原对象
console.log(Reflect.get(myObject, 'zzz')) // undefined
// 说明2的例子如下:
const otherObject = {
foo: 3,
bar: 4
}
console.log(Reflect.get(myObject, 'baz', otherObject)) // 7
// 说明3的例子如下:
console.log(Reflect.get(1, 'baz')) // TypeError: Reflect.get called on non-object
Reflect.has(target, name)
- Reflect.has方法对应name in obj里面的in运算符。
- 如果 Reflect.has() 方法的第一个参数不是对象,会报错。
// 说明1的例子如下:
var myObject = {
foo: 1,
}
console.log(Reflect.has(myObject, 'foo')) // true
console.log(Reflect.has(myObject, 'zzz')) // false
// 说明2的例子如下:
console.log(Reflect.has(1, 'baz')) // TypeError: Reflect.has called on non-object
Reflect.deleteProperty(target, name)
- Reflect.deleteProperty方法等同于delete obj[name],用于删除对象的属性。
- 注意:**如果删除成功,或者被删除的属性不存在,返回 true ;删除失败,被删除的属性依然存在,返回 false **
- 如果 Reflect.deleteProperty() 方法的第一个参数不是对象,会报错。
// 说明1,2的例子如下:
var myObject = {
foo: 1,
}
console.log(Reflect.deleteProperty(myObject, 'foo')) // true
console.log(Reflect.deleteProperty(myObject, 'zzz')) // true
// 此时的myObject 就是{}
Reflect.construct(target, args)
- Reflect.construct 方法等同于 new target(…args),这提供了一种不使用 new ,来调用构造函数的方法。
- 如果 Reflect.construct () 方法的第一个参数不是对象,会报错。
// 说明1的例子如下:
function Greeting(name) {
this.name = name;
}
// new 的写法
const instance = new Greeting('张三');
// Reflect.construct 的写法
const instance1 = Reflect.construct(Greeting, ['张三']); // {name: '张三'}
// 说明2的例子如下:
console.log(Reflect.construct(1, 'baz')) // TypeError: Reflect.construct called on non-object
实现观察者模式
// 这里就是简单观察者的核心逻辑,主要实现两个功能,一个就是observe,另一个就是observable
// 先定义了一个Set 集合,所有观察者函数都放进这个集合。
// observable 函数返回一个原始对象的 Proxy 代理,拦截赋值操作,触发充当观察者的各个函数
// 拦截函数 set 之中,会自动执行所有观察者
const queuedObservers = new Set();
const observe = fn => queuedObservers.add(fn);
const observable = obj => new Proxy(obj, {set});
function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
queuedObservers.forEach(observer => observer());
return result;
}
// 使用如下:
const person = observable({
name: '张三',
age: 20
});
function print() {
console.log( ${person.name}, ${person.age} )
}
observe(print);
person.name = '李四';