遍历对象的方法有很多种,比如使用for in,Object.keys, Object.entries, Reflect.ownKeys等, 看似效果都差不多,但其实各有用途。为了区别这些方法,今天我要以遍历一个class实例对象上的方法和属性为例。
一、class实例对象方法有什么特殊性
我们都知道class的实例对象的属性存在于实例对象,而方法存在于实例对象的原型上。按照常规,当我们用for in遍历一个实例对象时,应该可以得到其原型上的属性和方法,但为什么结果与我们预期不相符呢? 例如:
class A {
a = 1,
function b () {
console.log(1)
}
}
const a = new A()
for (const k in a) {
console.log(k)
}
// 结果只得到了a,而没有得到b
这个现象的原因是for in只能以任意顺序迭代一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性。而class实例对象上的方法在被创建时是被设置为不可枚举的。因此我们需要使用其他的手段来获取实例对象的key。
二、获取对象key的方法
常用的获取对象key的方法有以下几种:
- Object.keys():返回一个给定对象自身的可枚举属性组成的数组。
- Object.entries():返回一个给定对象自身可枚举属性的键值对数组,其排列与使用for in循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。
- Object.getOwnPropertyNames():返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值作为名称的属性)组成的数组。
- Reflect.ownKeys():返回一个由目标对象自身的属性键组成的数组。
可以看出,Object.keys与Object.entries都只能够获得可枚举属性,因此不能在遍历class实例方法中使用。而Object.getOwnPropertyNames与Reflect.ownKeys的区别在于后者可以得到symbol的键,而前者不行,所以一般情况下这两种方法都可以使用,特殊用到synbol的情况下还需要具体分析。
三、遍历class实例对象属性和方法的方案
class A {
a = 1,
function b () {
console.log(1)
}
}
const a = new A()
// 使用for in遍历实例属性
for (const k in a) {
console.log(k)
}
// 先使用Object.getPrototypeOf获取实例原型
const proto = Object.getPrototypeOf(a)
// 再使用Object.getOwnPropertyNames或Reflect.ownKeys获取原型上的方法
const keys = Reflect.ownKeys(proto)