对象基本方法
JS语法操作对象时,本质上是调用一个内部封装好的函数,该函数中又会调用对象的基本方法
,通过官方文档可以看到基本方法
。在过去,这些对象的基本方法
是不会对外暴露的。
如下面这段代码,使用JS语法给对象赋值,这种语法会触发JS内部方法,该方法最终会触发对象基本方法
[[Set]]
let obj = { name: "田本初" }
obj.age = 23
Reflect
Reflect
使开发者可以不使用JS语法的方式操作对象,而是直接调用对象基本方法
。
通过 mdn文档 可以看到基本方法
对应 Reflect
的方法名,如 [[Get]] 对应 get(),[[Set]] 对应 set()。
这里以 [[Get]]
举例并通过 es文档 详细分析:
const obj = {a: 1,b: 2,get c() {return this.a + this.b}
}
console.log(obj.c); // 3
console.log(Reflect.get(obj, 'c')); // 3
[[Get]]
本身有两个参数,propertyKey
为对象key, Receiver
则为this指向。
通过JS语法(obj.key)读取对象时Receiver
默认就是对象本身,无法修改this指向,但通过 Reflect
可以修改:
const obj = {a: 1,b: 2,get c() {return this.a + this.b}
}
console.log(obj.c); // 3
console.log(Reflect.get(obj, 'c', { a: 10, b: 20 })); // 30
Reflect
通常与 Proxy
配合使用,Proxy
可以看本人另一篇文章:Object.defineProperty与Proxy的对比并通过Vue2、3的实现证明Proxy性能优于Object.defineProperty
下面举例,使用 Proxy
代理对象,此时 this
指向就会出现问题
const obj = {a: 1,b: 2,get c() {return this.a + this.b}
}const p = new Proxy(obj, {get(target, key) {console.log('get', key);return target[key];}
})p.c
在访问c时,虽然使用了a和b,但this仍指向原对象obj而非代理对象p,没有触发对a和b的监听,所以控制台只打印了c。使用 Reflect
手动更正 this 指向即可:
const obj = {a: 1,b: 2,get c() {return this.a + this.b}
}const p = new Proxy(obj, {get(target, key, receiver) {console.log('get', key);return Reflect.get(target, key, receiver);}
})p.c
再比如使用 Object.keys
获取对象键名集合时,默认会忽略类型为Symbol
和不可枚举的属性。
查看 es文档 中Object.keys
的实现
继续查看EnumerableOwnProperties
,可以发现默认只取类型为string且可枚举的键
如果不想采用默认的 Object.keys
实现,可以通过 Reflect
直接使用对象的基本方法 [[OwnPropertyKeys]]
常用方法
-
Reflect.apply(target, thisArgument, argumentsList)
-
作用:调用一个目标函数,并指定
this
和参数。 -
示例:
function sum(a, b) {return a + b; } console.log(Reflect.apply(sum, null, [1, 2])); // 输出 3
-
-
Reflect.construct(target, argumentsList[, newTarget])
-
作用:等同于
new target(...argumentsList)
,但更具灵活性。 -
示例:
class MyClass {constructor(name) {this.name = name;} } const obj = Reflect.construct(MyClass, ['John']); console.log(obj.name); // 输出 'John'
-
-
Reflect.defineProperty(target, propertyKey, attributes)
-
作用:为对象定义属性,类似于
Object.defineProperty
。 -
示例:
const obj = {}; Reflect.defineProperty(obj, 'name', {value: 'John',writable: true,configurable: true,enumerable: true }); console.log(obj.name); // 输出 'John'
-
-
Reflect.deleteProperty(target, propertyKey)
-
作用:删除对象的属性,类似于
delete obj[propertyKey]
。 -
示例:
const obj = { name: 'John' }; Reflect.deleteProperty(obj, 'name'); console.log(obj.name); // 输出 undefined
-
-
Reflect.get(target, propertyKey[, receiver])
-
作用:获取对象的属性值,类似于
target[propertyKey]
。 -
示例:
const obj = { name: 'John' }; console.log(Reflect.get(obj, 'name')); // 输出 'John'
-
-
Reflect.set(target, propertyKey, value[, receiver])
-
作用:设置对象的属性值,类似于
target[propertyKey] = value
。 -
示例:
const obj = {}; Reflect.set(obj, 'name', 'John'); console.log(obj.name); // 输出 'John'
-
-
Reflect.has(target, propertyKey)
-
作用:检查对象是否具有某个属性,类似于
propertyKey in target
。 -
示例:
const obj = { name: 'John' }; console.log(Reflect.has(obj, 'name')); // 输出 true
-
-
Reflect.ownKeys(target)
-
作用:返回一个包含所有自身属性(包括不可枚举属性但不包括 Symbol 属性)的数组,类似于
Object.getOwnPropertyNames
和Object.getOwnPropertySymbols
的组合。 -
示例:
const obj = { name: 'John', age: 30 }; console.log(Reflect.ownKeys(obj)); // 输出 ['name', 'age']
-
与Proxy对比
Proxy
可以看本人另一篇文章:Object.defineProperty与Proxy的对比并通过Vue2、3的实现证明Proxy性能优于Object.defineProperty
Reflect
只能调用对象的基本操作
,比如属性的读取、设置、删除等。Reflect
不会对对象的行为做任何自定义或修改。它的作用只是将 JS 中的内置的对象基本操作标准化为方法,例如,Reflect.get() 只是返回对象的某个属性的值,不会更改对象的行为。
Proxy
用于 拦截和修改 对象。可以自定义对象的行为,甚至修改对象的默认操作(如属性读取、赋值等)。例如,使用 Proxy 的 get 捕捉器可以改变对象属性的获取方式,使得在读取属性时执行一些额外逻辑或返回自定义的值。