可以把获取属性的这些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私有属性。当然getOwnPropertyNames
和 getOwnPropertySymbols
这两个是一对,各自访问各自的那一部分属性,二者加起来恰恰就是所有属性。
以上是第一部分,很好记忆,接着来看看第二部分,即自身属性和原型属性都能访问的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