5分钟理清遍历对象的7种方式

214 阅读2分钟
本篇内容相关的7种方法: Object.keyObject.valuesObject.entriesObject.ownPropertyNamesObject.ownPropertySymbolsReflect.ownKeysfor...in
1)几乎所有的方法都不能遍历 继承属性 (原型链上的属性), 特例: for...in 可以遍历 继承属性
2)为了方便记忆我把对象的属性分类三种:普通可枚举属性(普通属性)、不可枚举属性、Symbol属性; 并把遍历的方法分为几类:
  1. 只能遍历普通属性:Object.keyObject.valuesObject.entries

  2. 普通属性 + 不可枚举:Object.ownPropertyNames

  3. 所有的Symbol属性(包括不可枚举的Symbol):Object.ownPropertySymbols

  4. 普通属性 + 不可枚举 + 所有的Symbol属性: Reflect.ownKeys

3)for...in, 可以遍历出所有的 普通属性 (包括继承的);
// 一般情况下原型链上的属性我是用不到的; 
// 用的时候要注意区分是否需要遍历继承的属性
for (const key in object) {
    if(Object.hasOwnProperty(key))
        const element = object[key];
        ... 
    }
}
测试代码:
    // 这里就直接粗暴的模拟了
    // 父级对象
    const parent = {
        a: 1, 
        b: 2, 
        c: 3,
        [Symbol('d')]: 4,
    };
    const proto = Object.create(parent);
    
    // 子级对象
    const obj = {
        f: 11, 
        i: 22, 
        j: 33,
        [Symbol('k')]: 44,
    }
    // 继承parent的属性
    obj.__proto__ = proto
    // 不可枚举的普通属性
    Object.defineProperty(obj, 'l', {
        enumerable: false,
        value: 55
    })
    // 不可枚举的Symbol属性
    Object.defineProperty(obj, Symbol('m'), {
        enumerable: false,
        value: 66
    })

    // 首先打印一下对象
    console.log(obj, 'obj')
    
    // 1. 普通属性
    console.log('遍历普通属性')
    console.log(Object.keys(obj), Object.values(obj), Object.entries(obj))
    
    // 2. 普通属性 + 不可枚举
    console.log('普通属性 + 不可枚举')
    console.log(Object.ownPropertyNames(obj))
    
    // 3. 遍历自身所有的Symbol属性
    console.log('遍历自身所有的Symbol属性')
    console.log(Object.ownPropertySymbols(obj))
    
    // 4. 遍历自身的所有属性
    console.log('遍历自身的所有属性')
    console.log(Reflect.ownKeys(obj))
    
    // 可遍历继承属性, 但不能遍历不可枚举 和 symbol属性
    for (const key in obj) { 
        console.log(key)
    }

注意: 虽然有些方法可以遍历出不可枚举属性,但是没有遍历出属性 __proto__,我猜应该是底层做了(与原型链上的属性)相关的判断吧-3-