JavaScript篇:对象遍历的N种姿势:从青铜到王者的花式操作指南 🏆

220 阅读4分钟

        大家好,我是江城开朗的豌豆,一名拥有6年以上前端开发经验的工程师。我精通HTML、CSS、JavaScript等基础前端技术,并深入掌握Vue、React、Uniapp、Flutter等主流框架,能够高效解决各类前端开发问题。在我的技术栈中,除了常见的前端开发技术,我还擅长3D开发,熟练使用Three.js进行3D图形绘制,并在虚拟现实与数字孪生技术上积累了丰富的经验,特别是在虚幻引擎开发方面,有着深入的理解和实践。

        我一直认为技术的不断探索和实践是进步的源泉,近年来,我深入研究大数据算法的应用与发展,尤其在数据可视化和交互体验方面,取得了显著的成果。我也注重与团队的合作,能够有效地推动项目的进展和优化开发流程。现在,我担任全栈工程师,拥有CSDN博客专家认证及阿里云专家博主称号,希望通过分享我的技术心得与经验,帮助更多人提升自己的技术水平,成为更优秀的开发者。

技术qq交流群:906392632

大家好,我是小杨,做了6年前端。今天要聊一个看似基础却暗藏玄机的话题——对象遍历。还记得我刚入行时,只会用for...in暴力遍历,结果被原型链上的属性坑得怀疑人生... 现在我把这些年的经验总结成段位升级指南,带你解锁对象遍历的正确姿势!


一、青铜段位:新手必会的三大基础操作

1. for...in —— 最熟悉的陌生人

const myGame = { name: '原神', type: 'RPG', rating: 4.5 };

for (let key in myGame) {
  console.log(`${key}: ${myGame[key]}`);
}
// 输出: name: 原神, type: RPG, rating: 4.5

坑爹警告:会遍历到原型链上的属性!

Object.prototype.company = '米哈游'; // 污染原型链
for (let key in myGame) {
  console.log(key); // 会多输出company!
}
// 防御方案:
for (let key in myGame) {
  if (myGame.hasOwnProperty(key)) { // 只遍历自身属性
    console.log(key);
  }
}

2. Object.keys() —— 干净利落的键集合

const keys = Object.keys(myGame); // ["name", "type", "rating"]
keys.forEach(key => {
  console.log(myGame[key]);
});

优点:自动过滤原型链属性,返回纯数组方便操作

3. Object.values() —— 只要值不要键(ES8新特性)

const values = Object.values(myGame); // ["原神", "RPG", 4.5]
values.forEach(value => {
  console.log('游戏属性值:', value);
});

二、白银段位:键值双收的进阶技巧

1. Object.entries() —— 一键打包键值对(ES8)

const entries = Object.entries(myGame); 
// [ ["name", "原神"], ["type", "RPG"], ["rating", 4.5] ]

entries.forEach(([key, value]) => {
  console.log(`键${key}对应值${value}`);
});

2. 与数组方法强强联合

// 快速转成Map
const gameMap = new Map(Object.entries(myGame));

// 过滤出数值属性
const numberProps = Object.entries(myGame)
  .filter(([_, value]) => typeof value === 'number')
  .map(([key]) => key); // ["rating"]

三、黄金段位:特殊场景的骚操作

1. 遍历Symbol属性(ES6+)

const id = Symbol('游戏ID');
const gameWithSymbol = {
  [id]: 123,
  name: '星穹铁道'
};

// 方法1:专取Symbol键
const symbolKeys = Object.getOwnPropertySymbols(gameWithSymbol); // [Symbol(游戏ID)]

// 方法2:取所有键(含Symbol)
const allKeys = Reflect.ownKeys(gameWithSymbol); // ["name", Symbol(游戏ID)]

2. 不可枚举属性的挖掘

const hiddenObj = Object.create(null, {
  secret: { value: '隐藏属性', enumerable: false }
});

// 常规方法拿不到
console.log(Object.keys(hiddenObj)); // []

// 必杀技:getOwnPropertyNames
console.log(Object.getOwnPropertyNames(hiddenObj)); // ["secret"]

四、王者段位:性能优化黑科技

1. 遍历速度实测对比

const bigObj = {};
for (let i = 0; i < 1000000; i++) {
  bigObj['key' + i] = i;
}

// 测试for...in
console.time('for...in');
for (let key in bigObj) {}
console.timeEnd('for...in'); // 约120ms

// 测试Object.keys+forEach
console.time('keys+forEach');
Object.keys(bigObj).forEach(() => {});
console.timeEnd('keys+forEach'); // 约90ms

结论:大数据量时Object.keys更优

2. 终极方案:迭代器协议

Object.prototype[Symbol.iterator] = function* () {
  for (const key of Object.keys(this)) {
    yield [key, this[key]];
  }
};

// 现在可以用for...of直接遍历对象!
for (const [key, value] of myGame) {
  console.log(key, value);
}

五、总结:选择指南(根据场景选武器)

场景推荐方法示例
需要遍历原型链for...in + 校验兼容老代码时
只要自有属性键Object.keys()转数组操作
需要同时获取键值Object.entries()转Map/批量处理
处理Symbol属性Reflect.ownKeys()元编程场景
超大数据量遍历Object.keys() + 循环性能敏感场景

血泪忠告

  1. 永远不要直接修改Object.prototype(除非你知道后果)
  2. 在Vue/React等框架中,慎用for...in遍历响应式对象
  3. 遇到JSON.stringify忽略某些属性时,检查是否可枚举

六、彩蛋:我遇到过的奇葩遍历问题

案例:曾经接手一个老项目,发现这段神奇代码:

const obj = { a: 1, b: 2 };
for (let key in obj) {
  if (key === 'a') {
    obj['c'] = 3; // 遍历时动态添加属性
  }
  console.log(key); // 输出啥?
}

猜猜输出结果?答案在评论区公布!


最后互动:你还在哪些场景下被对象遍历坑过?或者有什么独门遍历技巧?欢迎在评论区Battle! 👊