一、可迭代
概念
在 JavaScript 中,可迭代对象是指实现了迭代器协议的对象。迭代器协议要求对象具有一个 [Symbol.iterator]()
方法,该方法返回一个迭代器对象。迭代器对象负责定义数据序列的访问方式,能够依次访问数据序列中的每个元素。
原理
当对一个可迭代对象进行迭代操作(如使用 for...of
循环)时,JavaScript 引擎会先调用对象的 [Symbol.iterator]()
方法获取迭代器对象。然后,通过不断调用迭代器对象的 next()
方法,获取数据序列中的下一个元素,直到迭代器返回 { done: true }
,表示迭代结束。
这种机制允许统一处理各种类型的数据集合,使得不同的数据结构可以以相同的方式进行遍历。
二、可枚举
概念
可枚举性是对象属性的一种特性,它决定了该属性是否可以通过某些遍历方式(如 for...in
循环、Object.keys()
等)被遍历到。在 JavaScript 中,每个对象的属性都有一个 enumerable
属性描述符,用于表示该属性是否可枚举。
原理
当使用 for...in
循环遍历对象的属性时,JavaScript 引擎会枚举对象自身及其原型链上所有 enumerable
为 true
的属性。对于 Object.keys()
方法,它只返回对象自身 enumerable
为 true
的属性名数组。
这一机制使开发者能够控制对象属性的可见性,以便在遍历操作中包含或排除某些属性。
三、可迭代的示例
内置可迭代对象
数组
数组是典型的可迭代对象。
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() 设置枚举性的属性 |
分类 | 内置可迭代对象、自定义可迭代对象 | 默认可枚举属性、显式设置可枚举性属性 |