在JavaScript中,Object对象已经提供了一些反射的能力,例如Object.keys()、Object.defineProperty()等方法,可以获取对象的属性,定义属性等。然而,Reflect反射对象的出现,是为了更好地支持和完善JavaScript的反射能力。
首先,Reflect提供了一些Object没有的功能。例如,Object.keys()不能获取对象的Symbol属性,而Reflect.ownKeys()可以。这使得Reflect的API在兼容性和功能性上更强大。例如:
const s = Symbol('foo');
const obj = {
a: 1,
b: 'string',
[s]: 1,
};
// 使用Object.keys()获取对象的key
Object.keys(obj);
// ['a', 'b']
// 使用Reflect.ownKeys()获取对象的key
Reflect.ownKeys(obj);
// ['a', 'b', Symbol(foo)]
其次,Reflect对于行为表现上也有所不同。例如,Object.defineProperty()在执行失败时会抛出一个错误,这可能会打断进程,我们需要使用try...catch来保证代码执行。而Reflect.defineProperty()则不会抛出错误,而是在失败时返回false。例如:
// 使用Object.defineProperty()定义属性
try {
Object.defineProperty(obj, prop, attr);
// success do some other logic
} catch(e) {
// fail
}
// 使用Reflect.defineProperty()定义属性
if (Reflect.defineProperty(obj, prop, attr)) {
// success do some other logic
} else {
// fail
}
最后,Reflect的出现,使得JavaScript的反射能力得以完善,有了相同的使用习惯,利于延续正常的编程逻辑。
补充:
在JavaScript中,反射是在程序运行中获取和动态操作自身内容的一项技术。Reflect是一个内置对象,提供了一系列操作对象的方法,这些方法都是静态的(类似Math),使用Reflect的方法可以做一些对象的基本操作。例如,Reflect.has(target, propertyKey)可以检测一个对象是否存在特定属性。1
const duck = {
name: 'Maurice',
color: 'white',
greeting: function() {
console.log(`Quaaaack! My name is ${this.name}`);
}
}
Reflect.has(duck, 'color'); // true
Reflect.has(duck, 'haircut'); // false
Reflect提供的是一整套反射能力API,它们的调用方式,参数和返回值都是统一风格的,我们可以使用Reflect写出更优雅的反射代码。在Reflect库出现之前我们只是利用分散的API完成一些动态编程的事情,Reflect使得反射真正成为一种标准化能力。2
Reflect对象上面的方法和Proxy上面都是一一对应的,参数也是完全相同的,因此在Proxy中可以使用Reflect来操作对象。2
new Proxy(obj, {
set(...args) {
return Reflect.set(...args);
},
get(...args) {
return Reflect.get(...args);
},
deleteProperty(...args) {
return Reflect.deleteProperty(...args);
},
has(...args) {
return Reflect.has(...args);
}
});
Reflect更强大之处在于它的元编程能力,有一个metadata的提案可以通过Reflect添加元数据信息,使用元数据编程能够更方便进行框架开发。2