可迭代对象
可迭代协议
ECMAScript 6 引入了可迭代协议(Iterable Protocol),允许对象定义或定制它们的迭代行为。一个对象要成为可迭代对象,必须实现 @@iterator
方法,即对象或其原型链上必须有一个键为 Symbol.iterator
的属性。
const iterableObject = {
[Symbol.iterator]() {
let step = 0;
return {
next() {
step++;
if (step <= 5) {
return { value: step, done: false };
}
return { value: undefined, done: true };
}
};
}
};
内置可迭代对象
ES6 中许多内置对象默认就是可迭代的,包括:
- Array
- String
- Map
- Set
- TypedArray
- arguments 对象
- DOM NodeList
// 数组是可迭代的
const arr = [1, 2, 3];
for (const item of arr) {
console.log(item);
}
// 字符串也是可迭代的
const str = 'hello';
for (const char of str) {
console.log(char);
}
迭代器协议
迭代器协议定义了产生一系列值的标准方式。一个对象要成为迭代器,必须实现 next()
方法,该方法返回一个包含两个属性的对象:
value
:迭代器返回的值done
:布尔值,表示迭代是否完成
function createIterator(array) {
let index = 0;
return {
next() {
return index < array.length
? { value: array[index++], done: false }
: { value: undefined, done: true };
}
};
}
const iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
自定义可迭代对象
我们可以创建自定义的可迭代对象,只需要实现 Symbol.iterator
方法:
class Range {
constructor(start, end, step = 1) {
this.start = start;
this.end = end;
this.step = step;
}
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
const step = this.step;
return {
next() {
if (step > 0 ? current <= end : current >= end) {
const value = current;
current += step;
return { value, done: false };
}
return { value: undefined, done: true };
}
};
}
}
const range = new Range(1, 5);
for (const num of range) {
console.log(num); // 1, 2, 3, 4, 5
}
可迭代对象的应用场景
可迭代对象在ES6中有多种应用场景:
- for...of循环:专门用于遍历可迭代对象
- 展开运算符:可以将可迭代对象展开为单独的元素
- 解构赋值:可以从可迭代对象中提取值
- Array.from():将可迭代对象转换为数组
- Map、Set、WeakMap、WeakSet构造函数:接受可迭代对象作为参数
// for...of
const set = new Set([1, 2, 3]);
for (const item of set) {
console.log(item);
}
// 展开运算符
const arr = [...'hello']; // ['h', 'e', 'l', 'l', 'o']
// 解构赋值
const [first, second] = new Set([1, 2, 3]);
console.log(first, second); // 1 2
// Array.from
const map = new Map([[1, 'one'], [2, 'two']]);
const arrayFromMap = Array.from(map); // [[1, 'one'], [2, 'two']]
生成器与可迭代对象
生成器函数返回的生成器对象既是迭代器又是可迭代对象,这使得创建可迭代对象更加简洁:
function* generateSequence(start, end) {
for (let i = start; i <= end; i++) {
yield i;
}
}
const sequence = generateSequence(1, 5);
for (const num of sequence) {
console.log(num); // 1, 2, 3, 4, 5
}
// 生成器对象既是迭代器又是可迭代对象
const anotherSequence = generateSequence(1, 3);
console.log(anotherSequence[Symbol.iterator]() === anotherSequence); // true
异步可迭代对象
ES2018 引入了异步迭代器和异步可迭代对象,用于处理异步数据流:
async function* asyncGenerateSequence(start, end) {
for (let i = start; i <= end; i++) {
// 模拟异步操作
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
(async () => {
const asyncSequence = asyncGenerateSequence(1, 3);
for await (const num of asyncSequence) {
console.log(num); // 1 (100ms后), 2 (200ms后), 3 (300ms后)
}
})();
可迭代对象的组合
可迭代对象可以组合使用,创建更复杂的数据处理管道:
function* take(iterable, count) {
let taken = 0;
for (const item of iterable) {
if (taken >= count) return;
yield item;
taken++;
}
}
function* filter(iterable, predicate) {
for (const item of iterable) {
if (predicate(item)) {
yield item;
}
}
}
function* map(iterable, mapper) {
for (const item of iterable) {
yield mapper(item);
}
}
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const result = take(
map(
filter(numbers, n => n % 2 === 0),
n => n * 2
),
3
);
console.log([...result]); // [4, 8, 12]
可迭代对象的性能考虑
在处理大型数据集时,可迭代对象比数组更节省内存,因为它们可以按需生成值,而不是一次性生成所有值:
function* generateLargeDataset() {
for (let i = 0; i < 1e6; i++) {
yield i;
}
}
// 内存高效,因为值是按需生成的
for (const num of generateLargeDataset()) {
if (num > 10) break;
console.log(num);
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益,请来信告知我们删除。邮箱:cc@cccx.cn