JS中枚举和迭代

一、可迭代

概念

在 JavaScript 中,可迭代对象是指实现了迭代器协议的对象。迭代器协议要求对象具有一个 [Symbol.iterator]() 方法,该方法返回一个迭代器对象。迭代器对象负责定义数据序列的访问方式,能够依次访问数据序列中的每个元素。

原理

当对一个可迭代对象进行迭代操作(如使用 for...of 循环)时,JavaScript 引擎会先调用对象的 [Symbol.iterator]() 方法获取迭代器对象。然后,通过不断调用迭代器对象的 next() 方法,获取数据序列中的下一个元素,直到迭代器返回 { done: true },表示迭代结束。

这种机制允许统一处理各种类型的数据集合,使得不同的数据结构可以以相同的方式进行遍历。

二、可枚举

概念

可枚举性是对象属性的一种特性,它决定了该属性是否可以通过某些遍历方式(如 for...in 循环、Object.keys() 等)被遍历到。在 JavaScript 中,每个对象的属性都有一个 enumerable 属性描述符,用于表示该属性是否可枚举。

原理

当使用 for...in 循环遍历对象的属性时,JavaScript 引擎会枚举对象自身及其原型链上所有 enumerabletrue 的属性。对于 Object.keys() 方法,它只返回对象自身 enumerabletrue 的属性名数组。

这一机制使开发者能够控制对象属性的可见性,以便在遍历操作中包含或排除某些属性。

三、可迭代的示例

内置可迭代对象

数组

数组是典型的可迭代对象。

dart 复制代码
const arr = [1, 2, 3];
for (const num of arr) {
    console.log(num); // 输出 1、2、3
}

数组的 [Symbol.iterator]() 方法返回一个迭代器,使得可以通过 for...of 循环依次访问数组元素。

字符串

字符串也是可迭代的。

rust 复制代码
const str = 'abc';
for (const char of str) {
    console.log(char); // 输出 'a'、'b'、'c'
}

Map 和 Set

它们都是可迭代的集合对象。

arduino 复制代码
const map = new Map([[ 'key1', 'value1' ], [ 'key2', 'value2' ]]);
for (const [key, value] of map) {
    console.log(key, value); // 输出 'key1 value1'、'key2 value2'
}

自定义可迭代对象

可以通过实现 [Symbol.iterator]() 方法创建自定义的可迭代对象。

kotlin 复制代码
class CustomIterable {
    constructor(data) {
        this.data = data;
    }
    [Symbol.iterator]() {
        let index = 0;
        return {
            next: () => {
                if (index < this.data.length) {
                    return {
                        value: this.data[index++],
                        done: false
                    };
                } else {
                    return {
                        done: true
                    };
                }
            },
            [Symbol.iterator]() {
                return this;
            }
        };
    }
}
​
const custom = new CustomIterable([10, 20, 30]);
for (const num of custom) {
    console.log(num); // 输出 10、20、30
}

四、可枚举的示例

默认可枚举的属性

对象的常规属性通常默认是可枚举的。

vbnet 复制代码
const obj = {
    name: 'John',
    age: 30
};
​
for (const key in obj) {
    console.log(key); // 输出 'name'、'age'
}

控制属性的可枚举性

使用 Object.defineProperty()Object.defineProperties() 方法可以控制属性的可枚举性。

php 复制代码
const obj = {};
​
Object.defineProperty(obj, 'secret', {
    value: 'hidden',
    enumerable: false
});
​
Object.defineProperty(obj, 'visible', {
    value: 'visible',
    enumerable: true
});
​
for (const key in obj) {
    console.log(key); // 只输出 'visible'
}

五、可迭代和可枚举的分类

可迭代的分类

内置可迭代对象

包括数组、字符串、Map、Set 等。这些是 JavaScript 内置的数据结构,天生支持迭代协议,可以直接使用 for...of 循环等迭代方式。

自定义可迭代对象

通过实现 [Symbol.iterator]() 方法,可以将自定义对象定义为可迭代的。这允许开发者创建具有特定迭代逻辑的对象。

可枚举的分类

默认可枚举属性

当使用常规方式(如对象字面量)定义对象属性时,这些属性默认是可枚举的。

显式设置可枚举性

使用 Object.defineProperty() 等方法可以显式地设置属性的 enumerable 特性,从而控制其是否可枚举。

六、总结

特性/分类 可迭代(Iterable) 可枚举(Enumerable)
概念 实现迭代器协议的对象,支持统一的迭代操作 对象属性的一种特性,决定属性是否可通过某些遍历方式被访问
原理 通过 [Symbol.iterator]() 方法返回迭代器,由迭代器定义数据序列的访问方式 通过属性描述符中的 enumerable 属性控制属性是否可被枚举
示例 数组、字符串、Map、Set 及自定义对象(通过实现 [Symbol.iterator]() 对象的常规属性(默认可枚举)、通过 Object.defineProperty() 设置枚举性的属性
分类 内置可迭代对象、自定义可迭代对象 默认可枚举属性、显式设置可枚举性属性
相关推荐
子兮曰14 小时前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰14 小时前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万14 小时前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝14 小时前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋15 小时前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁16 小时前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄16 小时前
JavaScript 隐式全局变量解析
javascript
汉堡大王952717 小时前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大17 小时前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师18 小时前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端