您现在的位置是:网站首页 > 对象枚举与迭代文章详情
对象枚举与迭代
陈川
【
JavaScript
】
18390人已围观
3549字
在JavaScript中,对象枚举与迭代是处理数据结构的基础操作。对象属性的遍历方式多样,不同方法适用于不同场景,而现代ES6+语法进一步简化了迭代流程。
对象属性的枚举方法
for...in循环
for...in
是遍历对象可枚举属性的经典方法,但会遍历原型链上的属性:
const person = {
name: 'Alice',
age: 28
};
Object.prototype.gender = 'female';
for (const key in person) {
console.log(key); // 输出 name, age, gender
}
可通过hasOwnProperty
过滤原型属性:
for (const key in person) {
if (person.hasOwnProperty(key)) {
console.log(key); // 只输出 name, age
}
}
Object.keys()
获取对象自身可枚举属性的数组:
const keys = Object.keys(person); // ['name', 'age']
keys.forEach(key => {
console.log(`${key}: ${person[key]}`);
});
Object.getOwnPropertyNames()
包含不可枚举属性(如数组length):
const arr = ['a', 'b'];
console.log(Object.getOwnPropertyNames(arr));
// ['0', '1', 'length']
现代迭代协议
Symbol.iterator
实现可迭代对象:
const myIterable = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
}
};
for (const value of myIterable) {
console.log(value); // 1, 2, 3
}
生成器函数
动态生成迭代序列:
function* idGenerator() {
let id = 0;
while(true) {
yield id++;
}
}
const gen = idGenerator();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
Map与Set的迭代
Map的三种迭代器
const map = new Map([
['key1', 'value1'],
['key2', 'value2']
]);
// 键值对迭代
for (const [key, value] of map.entries()) {
console.log(`${key} => ${value}`);
}
// 单独获取键或值
console.log([...map.keys()]); // ['key1', 'key2']
console.log([...map.values()]); // ['value1', 'value2']
Set的迭代特性
const set = new Set([1, 2, 3]);
// Set可直接迭代
for (const value of set) {
console.log(value); // 1, 2, 3
}
// 转换为数组
console.log([...set]); // [1, 2, 3]
性能比较与实践建议
遍历速度测试
const bigObj = {};
for (let i = 0; i < 1000000; i++) {
bigObj[`key${i}`] = i;
}
// 测试for...in
console.time('for...in');
for (const key in bigObj) {}
console.timeEnd('for...in');
// 测试Object.keys
console.time('Object.keys');
Object.keys(bigObj).forEach(() => {});
console.timeEnd('Object.keys');
典型结果:
for...in
: ~120msObject.keys
+forEach
: ~90ms
不可枚举属性的处理
const obj = {};
Object.defineProperty(obj, 'hidden', {
value: 'secret',
enumerable: false
});
// 使用Reflect.ownKeys获取所有键
console.log(Reflect.ownKeys(obj)); // ['hidden']
特殊场景处理
类数组对象迭代
function printArgs() {
// arguments是类数组对象
Array.from(arguments).forEach(arg => {
console.log(arg);
});
}
printArgs(1, 'a', true);
深度遍历对象
递归实现深度迭代:
function* deepTraverse(obj) {
for (const [key, value] of Object.entries(obj)) {
yield [key, value];
if (typeof value === 'object' && value !== null) {
yield* deepTraverse(value);
}
}
}
const nestedObj = { a: 1, b: { c: 2, d: { e: 3 } } };
for (const [key, value] of deepTraverse(nestedObj)) {
console.log(`${key}: ${value}`);
}
迭代器的高级应用
组合迭代器
function* chainIterables(...iterables) {
for (const iterable of iterables) {
yield* iterable;
}
}
const combined = chainIterables(
[1, 2],
new Set([3, 4]),
'hello'
);
console.log([...combined]); // [1, 2, 3, 4, 'h', 'e', 'l', 'l', 'o']
异步迭代
处理流式数据:
async function* asyncNumbers() {
let i = 0;
while (i < 3) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i++;
}
}
(async () => {
for await (const num of asyncNumbers()) {
console.log(num); // 0, 1, 2 (间隔100ms)
}
})();
上一篇: 属性描述符
下一篇: 初始化ECharts实例