大家好,我是江城开朗的豌豆,一名拥有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() + 循环 | 性能敏感场景 |
血泪忠告:
- 永远不要直接修改
Object.prototype(除非你知道后果) - 在Vue/React等框架中,慎用
for...in遍历响应式对象 - 遇到
JSON.stringify忽略某些属性时,检查是否可枚举
六、彩蛋:我遇到过的奇葩遍历问题
案例:曾经接手一个老项目,发现这段神奇代码:
const obj = { a: 1, b: 2 };
for (let key in obj) {
if (key === 'a') {
obj['c'] = 3; // 遍历时动态添加属性
}
console.log(key); // 输出啥?
}
猜猜输出结果?答案在评论区公布!
最后互动:你还在哪些场景下被对象遍历坑过?或者有什么独门遍历技巧?欢迎在评论区Battle! 👊