Reflect API 和 Object 静态方法的对比
介绍
Reflect 内置对象提供了与 JavaScript 对象交互的方法,这些方法与 Proxy handler(捕获器)的方法对应。但 Reflect 不是一个函数对象,因此不能当构造函数。
Proxy 一般需要和 Reflect 联合使用,Proxy 对象拦截操作,Reflect 完成默认行为,然后就可以在 Proxy 对象中部署额外的功能。
apply 函数
在 Reflect 之前,使用 Function.prototype.apply() 方法调用具有给定 this 值和作为数组(或类似数组的对象)提供参数的函数。
Function.prototype.apply.call(Math.floor, undefined, [1.75]); // 1
使用 Reflect.apply 之后更易读和理解:
Reflect.apply(Math.floor, undefined, [1.75]) // 1
Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]) // "hello"
Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index // 4
Reflect.apply(''.charAt, 'ponies', [3]) // "i"
检查属性定义是否成功
使用 Object.defineProperty,如果成功则返回传递给函数的对象,否则抛出 TypeError,需要使用 try...catch 块来捕获定义属性时发生的错误。
try {
Object.defineProperty(target, prop, descriptor) // success
} catch (err) {
// failure
}
而 Reflect.defineProperty 返回一个布尔值表示成功状态,所以可以替换成 if...else 块:
if (Reflect.defineProperty(target, prop, descriptor)) {
// success
} else {
// failure
}
注意:如果 target 不是 Object,Object.defineProperty 和 Reflect.defineProperty 都会抛出 TypeError 异常。
操作函数化
- Reflect.has() 判断一个对象是否存在某个属性,和 in 运算符的功能完全相同。如果 target 不是 Object,则抛出 TypeError。
Reflect.has(target, prop)
// 相当于
prop in target
- Reflect.deleteProperty() 删除一个对象的某个属性,和 delete 运算符的功能完全相同。如果 target 不是 Object,则抛出 TypeError。
Reflect.deleteProperty(target, prop)
// 相当于
delete target[prop]
与 Object 对象的静态方法对比
Reflect 上的一些方法对应于 ES2015 之前的 Object 上的静态方法。有些在 Reflect 上的新方法,Object 上没有;而有些在 Object 上的方法 Reflect 上没有。
- defineProperty()(见上文),Object 和 Reflect 都有。
- defineProperties(),只有 Object 有。如果描述符既没有 value、writable、get 和 set 键,则将其视为数据描述符。如果描述符同时具有 value 或 writable 以及 get 或 set 键,则会引发异常。如果对象不是 Object 类型,会抛出 TypeError。
Object.defineProperties(obj, propsAndDescriptors)
- has()(见上文),只有 Reflect 有。
- deleteProperty()(见上文),只有 Reflect 有。
- get(),只有 Reflect 有。返回属性的值。如果 target 不是 Object,则抛出 TypeError。
Reflect.get(target, prop[, receiver])
- set(),只有 Reflect 有。如果在对象上成功设置了属性,则 Reflect.set() 返回 true,否则返回 false。如果 target 不是 Object,则抛出 TypeError。
Reflect.set(target, prop, value[, receiver])
- keys(),只有 Object 有。返回一个可枚举的属性键的字符串数组。如果目标不是对象,在 ES5 中抛出 TypeError,在 ES2015 中则将其强制转换为对象。
Object.keys(obj)
- ownKeys(),只有 Reflect 有。返回一个由目标对象自身的属性键组成的数组。等同于 Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))。
Reflect.ownKeys(target)
- getOwnPropertyDescriptor(),Object 和 Reflect 都有。
Object.getOwnPropertyDescriptor(obj, prop)
如果指定的属性存在于对象上,则返回该属性描述符,如果不存在则返回 undefined。在 ES5 中,如果的第一个参数不是对象(而是原始类型),会抛出 TypeError。而在 ES2015,第一个的参数不是对象类型会被强制转换为对象。
Reflect.getOwnPropertyDescriptor(target, prop)
如果第一个参数不是对象(而是原始类型),会抛出 TypeError。
- getOwnPropertyDescriptors(),只有 Object 有。获取指定对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。
Object.getOwnPropertyDescriptors(obj)
浅拷贝一个对象:Object.assign() 方法只能拷贝源对象的可枚举的自身属性,同时拷贝时无法拷贝属性的描述符,而且访问器属性会被转换成数据属性,也无法拷贝源对象的原型,Object.getOwnPropertyDescriptors(obj) 方法配合 Object.create() 方法则可以实现这些。
Object.create( Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj) );
- getPrototypeOf(),Object 和 Reflect 都有。
Object.getPrototypeOf(obj)
返回给定对象的原型。如果没有继承属性,则返回 null。在 ES5 中,如果参数不是一个对象类型,会抛出 TypeError 异常。在 ES2015 中,参数会被强制转换为一个 Object。
Reflect.getPrototypeOf(target)
如果 target 不是 Object,会抛出 TypeError 异常。
- setPrototypeOf(),Object 和 Reflect 都有。
Object.setPrototypeOf(obj, prototype)
设置对象的新原型,并返回该对象。如果 prototype 不是一个对象或 null,或 obj 参数是不可扩展的或是一个不可修改原型的对象,例如 Object.prototype 或 window,会抛出 TypeError 异常。
Reflect.setPrototypeOf(target, prototype)
返回一个布尔值,指示原型是否成功设置。如果 prototype 不是一个对象或 null,会抛出 TypeError 异常。如果 obj 参数是不可扩展的或是一个不可修改原型的对象,例如 Object.prototype 或 window,会返回 false,而不是抛出 TypeError 异常。
- isExtensible(),Object 和 Reflect 都有。返回一个 Boolean 值,指示一个对象是否是可扩展的(是否可以在它上面添加新的属性)。默认情况下,对象是可扩展的:即可以为他们添加新的属性,并且可以重新分配其原型。Object.preventExtensions,Object.seal 或 Object.freeze 方法都可以使一个对象变为不可扩展。
Object.isExtensible(obj)
在 ES5 中,如果参数不是对象(而是原始类型),会抛出 TypeError。在 ES2015 中,如果传递了非对象参数,将返回 false 而没有任何错误,因为根据定义,原始类型是不可变的。
Reflect.isExtensible(target)
如果参数不是对象(而是原始类型),会抛出 TypeError。
- preventExtensions(),Object 和 Reflect 都有。阻止对象添加新属性和对象的原型被重新分配。当将新属性添加到不可扩展对象将静默失败,严格模式下会抛出 TypeError。当为不可扩展对象重新分配原型时,会抛出 TypeError。
Object.preventExtensions(obj)
使对象不可扩展并返回该对象。在 ES5 中,如果参数不是一个对象类型(而是原始类型),会抛出 TypeError 异常。在 ES2015 中,非对象参数将被视为一个不可扩展的普通对象,因此会被直接返回。
Reflect.preventExtensions(target)
返回一个 Boolean 值指示目标对象是否成功被设置为不可扩展。如果参数不是一个对象类型(而是原始类型),会抛出 TypeError 异常。
转载自:https://juejin.cn/post/7149111768944476196