javascript遍历对象的方法

139 阅读3分钟

javascript遍历对象的方法

遍历对象的方法有:

  1. for...in 包含原型链 可枚举(如果它们没有被对象自身的同名属性所遮蔽)
  2. for...of 需要部署迭代器(一般用来遍历部署了迭代器的数据结构)
  3. Object.keys() 不包含原型链 可枚举
  4. Object.values() 不包含原型链 可枚举
  5. Object.entries() 不包含原型链 可枚举
  6. Object.getOwnPropertyNames() 不包含原型链 可枚举和不可枚举
  7. Object.getOwnPropertyDescriptors() 不包含原型链 可枚举和不可枚举
  8. Object.getOwnPropertySymbols() 不包含原型链 可枚举和不可枚举 仅仅包含symbol
  9. Reflect.ownKeys() 不包含原型链

测试代码

const parentObj = new Object();
Object.defineProperties(parentObj, {
  '10': {
    enumerable:false,
    value:'10'
  },
  '11': {
    enumerable: true,
    value:'11'
  },
  [Symbol('a')]:{
    enumerable: true,
    value:'symbol_origin_enumerable'
  },
  [Symbol('b')]:{
    enumerable: false,
    value:'symbol_origin_noEnumerable'
  },
});
function A(){ }
A.prototype = parentObj
const childObj = new A()
Object.defineProperties(childObj, {
  '00': {
    enumerable:false,
    value:'00'
  },
  '01': {
    enumerable: true,
    value:'01'
  },
  [Symbol('c')]:{
    enumerable: true,
    value:'symbol_noOrigin_enumerable'
  },
  [Symbol('d')]:{
    enumerable: false,
    value:'symbol_noOrigin_noEnumerable'
  },
});

归类

  • for...of 需要单独实现
  • 可以遍历原型链
    • for in
  • 不可遍历原型链
    • 只能遍历可枚举
      1. Object.keys() 不包含原型链 可枚举
      2. Object.values() 不包含原型链 可枚举
      3. Object.entries() 不包含原型链 可枚举
    • 包含不可枚举
      1. Object.getOwnPropertyNames() 不包含原型链 可枚举和不可枚举
      2. Object.getOwnPropertyDescriptors() 不包含原型链 可枚举和不可枚举
      3. Object.getOwnPropertySymbols() 不包含原型链 可枚举和不可枚举 仅仅包含symbol
      4. Reflect.ownKeys() 不包含原型链 可枚举和不可枚举

需要注意的点

  • 只有 for...in 循环会遍历原型链上的可枚举属性,而其他方法和表达式都仅考虑对象自身的属性。
  • symbol类型有专用的api进行读取,Json.stringify的时候symbol会被排除在外
  • for...of需要部署迭代器才能对对象进行属性读取
  • 有Own的方法都只能读取自身的属性
  • Object.getOwnPropertyDescriptors() Descriptors(英译中:描述符)获取的是属性配置对象,默认的配置如下
    const a = {
      name:'另老贝'
    }
    console.log(Object.getOwnPropertyDescriptors(a))
    /*
      {
        name: {
          value: '另老贝',
          writable: true,//如果与属性关联的值可以使用赋值运算符更改,则为 true。默认为 false。
          enumerable: true,//如果此属性在枚举相应对象的属性时应显示出来,则为 true。默认为 false。
          configurable: true//如果此属性描述符的类型可以更改并且属性可以从相应的对象中删除,则为 true。默认为 false。
        }
      }
    */
    
  • 给对象部署迭代器

    在JavaScript中,迭代器的标准实现需要满足以下要求: 迭代器对象:必须是一个对象,该对象拥有一个 next() 方法。 next() 方法:当调用此方法时,它应返回一个对象,该对象具有两个属性:value 和 done。 value:表示当前迭代步骤的值。 done:是一个布尔值,表示迭代是否已完成。如果迭代已完成,则 done 为 true,且 value 的值(如果有的话)是迭代结束后的返回值(通常是 undefined)。 可迭代对象:要实现自定义的可迭代对象,你需要在该对象上定义一个 @@iterator 方法,该方法通过 Symbol.iterator 访问,并返回一个迭代器对象。

    //使用yield
    const testObj = {
      name:'pkq',
      age:18,
      *[Symbol.iterator]() {
        const keys = Reflect.ownKeys(this); // 获取对象自身的所有属性键(包括不可枚举属性)
        for (const key of keys) {
          yield this[key]; // 使用 yield 关键字逐个返回属性值
        }
      }
    }
    for(let i of testObj){
      console.log(i)
    }
    
    
    //不使用yield
    obj[Symbol.iterator] = function() {
      const keys = Object.keys(this);
      let index = 0;
      
      return {
        next: function() {
          if (index < keys.length) {
            return {
              value: this[keys[index++]],
              done: false
            };
          } else {
            return {
              value: undefined,
              done: true
            };
          }
        }.bind(this) // 使用 bind 来确保 next 方法中的 this 指向正确的对象
      };
    };