Reflect.has / Reflect.ownKeys / in / getOwnPropertyDescriptor 等几种获取对象属性的区别

可以把获取属性的这些API分成几部分:

  • 均可以获取普通属性,这是必然的…
  • 是否可以获取不可枚举属性
  • 是否可以获取Symbol属性
  • 是否可以获取存在于原型上的属性

而具备访问对象属性的api分为以下部分

  • Reflect 静态方法(has() / ownKeys() 等)
  • Object 静态方法(getOwnPropertyNames 等)
  • in 操作符,包含直接使用或者for in 使用
  • 当然还有.操作符或者[‘key’]这样直接访问

可能ES标准委也觉得这么多访问属性的api多少有些难为开发者。所以api命名的时候,若只能访问自身的属性,而非原型的属性,一般会加上个Own前缀,比如

  • Object.getOwnPropertyDescriptor()
  • Object.getOwnPropertyDescriptors()
  • Object.getOwnPropertyNames()
  • Object.getOwnPropertySymbols()
  • Reflect.getOwnPropertyDescriptor()
  • Reflect.ownKeys()
  • objectInstance.hasOwnProperty()

以上这些api均不能访问对象的原型属性和方法,而且庆幸的是,这些api均可以访问到普通属性,不可枚举属性,以及Symbol私有属性。当然getOwnPropertyNamesgetOwnPropertySymbols 这两个是一对,各自访问各自的那一部分属性,二者加起来恰恰就是所有属性。

以上是第一部分,很好记忆,接着来看看第二部分,即自身属性和原型属性都能访问的api。事实上,没有一个api能够直接获取到包含自身属性和原型属性的集合。

// 不存在能够获取所有属性集合的api.
const allKeys = someObject.getSelfAndPrototypeProperties();

但存在两个api,可以检测所有属性中的任一个属性是否存在于对象中。

  • Reflect.has()
  • in 操作符

静态方法 Reflect.has() 作用与 in 操作符 相同。

以上两个api可以检测到包含自身属性和原型属性,无论普通 / 不可枚举 / 原型。可以把这二者看做是第二部分。

接下来是第三部分,反而是我们经常会用到的:

  • Object.keys()
  • for in 循环

以上两个api均不能访问到不可枚举以及Symbol私有属性。当然for in可以获取到原型属性,而Object.keys不可以。

const foo = {a: 1};
// bar 的原型是foo。bar自身有一个可枚举属性b
const bar = Object.create(foo, {b: {value: 2, enumerable: true}})

console.log(Object.keys(bar)); // b
for (let attr in bar) {console.log(attr)} // b a

最后,使用.操作符和['']的方式访问属性。这是可以访问到普通、不可枚举 、私有以及原型属性。区别于第二部分,由于这两种方式可以赋值,若当前属性是来自于原型,那么赋值之后会怎么样呢?

const foo = {a: 1};
// bar 的原型是foo。bar自身有一个可枚举属性b
const bar = Object.create(foo, {b: {value: 2, enumerable: true}})

bar.a = 3;
console.log(bar.a); // 3
console.log(foo.a); // 1

// 不会多遍历一次a
for (let attr in bar) {console.log(attr)} // b a

如上赋值操作不会修改原型属性。但如果原型属性是只读的呢?

const foo = {a: 1};
Object.freeze(foo);
// bar的原型属性a是只读的。
Object.getOwnPropertyDescriptor(foo, 'a'); // {value: 1, writable: false, enumerable: true, configurable: false}

const bar = Object.create(foo, {b: {value: 2, enumerable: true}})

bar.a = 3;

console.log(bar.a); // 猜猜是多少?

参考:

最后答案参考这里…
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值