TypechoJoeTheme

至尊技术网

统计
登录
用户名
密码

深入理解JavaScript迭代器模式:从基础到实战应用

2025-09-05
/
0 评论
/
4 阅读
/
正在检测是否收录...
09/05

深入理解JavaScript迭代器模式:从基础到实战应用

什么是迭代器模式?

迭代器模式(Iterator Pattern)是JavaScript中一种行为型设计模式,它提供了一种顺序访问聚合对象中各个元素的方法,而又不暴露该对象的内部表示。在ES6之后,JavaScript通过Symbol.iterator协议原生支持了迭代器模式。

javascript
// 基础迭代器示例
const array = [1, 2, 3];
const iterator = arraySymbol.iterator;

console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }

为什么需要迭代器?

  1. 统一访问接口:无论是数组、Map、Set还是自定义数据结构,都可以通过统一的for...of语法遍历
  2. 惰性计算:只有在调用next()时才会计算下一个值,适合处理大数据集
  3. 解耦遍历逻辑:将集合的遍历操作与业务逻辑分离

实现自定义迭代器的三种方式

方法一:通过生成器函数

javascript
class PaginatedResults {
constructor(data, pageSize = 5) {
this.data = data;
this.pageSize = pageSize;
}

*Symbol.iterator {
let currentPage = 0;
while (currentPage * this.pageSize < this.data.length) {
yield this.data.slice(
currentPage * this.pageSize,
(currentPage + 1) * this.pageSize
);
currentPage++;
}
}
}

// 使用示例
const pager = new PaginatedResults([...Array(23).keys()]);
for (const page of pager) {
console.log('当前页:', page);
}

方法二:经典迭代器对象

javascript
class Tree {
constructor(value, children = []) {
this.value = value;
this.children = children;
}

Symbol.iterator {
let stack = [this];
let index = 0;

return {
  next: () => {
    if (stack.length === 0) {
      return { done: true };
    }

    const node = stack.shift();
    stack.unshift(...node.children);
    return {
      value: node.value,
      done: false
    };
  }
};

}
}

// 使用示例
const tree = new Tree(1, [
new Tree(2, [new Tree(4)]),
new Tree(3)
]);

for (const value of tree) {
console.log('树节点值:', value);
}

方法三:异步迭代器实现

javascript
class AsyncDataFetcher {
constructor(urls) {
this.urls = urls;
}

async *Symbol.asyncIterator {
for (const url of this.urls) {
const response = await fetch(url);
const data = await response.json();
yield data;
}
}
}

// 使用示例
(async () => {
const fetcher = new AsyncDataFetcher([
'/api/users',
'/api/products'
]);

for await (const data of fetcher) {
console.log('获取的数据:', data);
}
})();

实战应用场景

场景一:分页加载优化

javascript
class LazyLoader {
constructor(loadAPI, batchSize = 10) {
this.loadAPI = loadAPI;
this.batchSize = batchSize;
this.cache = [];
this.currentIndex = 0;
}

async *load() {
while (true) {
if (this.currentIndex >= this.cache.length) {
const newData = await this.loadAPI(
Math.floor(this.cache.length / this.batchSize),
this.batchSize
);
if (!newData.length) break;
this.cache.push(...newData);
}
yield this.cache[this.currentIndex++];
}
}
}

// 使用示例
const userLoader = new LazyLoader(async (page, size) => {
// 模拟API调用
return Array(size).fill(0).map((_, i) => 用户_${page*size + i});
});

(async () => {
for await (const user of userLoader.load()) {
console.log('当前用户:', user);
}
})();

场景二:复杂数据结构遍历

javascript
class Matrix {
constructor(width, height, initial = 0) {
this.width = width;
this.height = height;
this.data = Array(height)
.fill()
.map(() => Array(width).fill(initial));
}

*Symbol.iterator {
for (let y = 0; y < this.height; y++) {
for (let x = 0; x < this.width; x++) {
yield { x, y, value: this.data[y][x] };
}
}
}

// 螺旋遍历迭代器
*spiral() {
let top = 0, bottom = this.height - 1;
let left = 0, right = this.width - 1;

while (top <= bottom && left <= right) {
  // 从左到右
  for (let x = left; x <= right; x++) {
    yield { x, y: top, value: this.data[top][x] };
  }
  top++;

  // 从上到下
  for (let y = top; y <= bottom; y++) {
    yield { x: right, y, value: this.data[y][right] };
  }
  right--;

  if (top <= bottom) {
    // 从右到左
    for (let x = right; x >= left; x--) {
      yield { x, y: bottom, value: this.data[bottom][x] };
    }
    bottom--;
  }

  if (left <= right) {
    // 从下到上
    for (let y = bottom; y >= top; y--) {
      yield { x: left, y, value: this.data[y][left] };
    }
    left++;
  }
}

}
}

// 使用示例
const matrix = new Matrix(5, 5);
let counter = 1;
for (const cell of matrix) {
matrix.data[cell.y][cell.x] = counter++;
}

console.log('螺旋遍历结果:');
for (const cell of matrix.spiral()) {
console.log((${cell.x},${cell.y}): ${cell.value});
}

高级技巧与性能优化

  1. 迭代器组合:通过组合多个迭代器实现复杂遍历逻辑
    javascript function* chainIterators(...iterators) { for (const iterator of iterators) { yield* iterator; } }

  2. 记忆化迭代器:缓存已遍历的结果避免重复计算javascript
    function createMemoizedIterator(source) {
    const cache = [];
    let sourceExhausted = false;

    return {
    next() {
    if (cache.length > 0) {
    return { value: cache.shift(), done: false };
    }
    if (sourceExhausted) return { done: true };

    const { value, done } = source.next();
    if (done) {
    sourceExhausted = true;
    return { done: true };
    }
    return { value, done: false };
    },
    peek() {
    if (cache.length === 0 && !sourceExhausted) {
    const { value, done } = source.next();
    if (!done) cache.push(value);
    else sourceExhausted = true;
    }
    return cache.length > 0
    ? { value: cache[0], done: false }
    : { done: true };
    }
    };
    }

  3. 无限序列生成:利用迭代器实现无限序列javascript
    function* fibonacci() {
    let [a, b] = [0, 1];
    while (true) {
    yield a;
    [a, b] = [b, a + b];
    }
    }

// 使用示例
const fib = fibonacci();
console.log('斐波那契数列:');
for (let i = 0; i < 10; i++) {
console.log(fib.next().value);
}

常见问题与解决方案

  1. 迭代器耗尽问题



    • 现象:同一个迭代器只能遍历一次
    • 解决:实现[Symbol.iterator]()方法返回新的迭代器
  2. 与数组方法的配合:javascript
    // 将迭代器转为数组
    const arr = [...myIterator];

    // 在迭代器上使用数组方法
    function iterMap(iterator, fn) {
    return {
    Symbol.iterator {
    const it = iteratorSymbol.iterator;
    return {
    next() {
    const { value, done } = it.next();
    return done
    ? { done: true }
    : { value: fn(value), done: false };
    }
    };
    }
    };
    }

  3. 错误处理:javascript
    class SafeIterator {
    constructor(iterator) {
    this.iterator = iterator;
    }

    next() {
    try {
    return this.iterator.next();
    } catch (error) {
    return { done: true, error };
    }
    }

    Symbol.iterator {
    return this;
    }
    }

迭代器模式在现代JavaScript开发中扮演着越来越重要的角色,特别是在处理异步数据流、大型数据集和复杂数据结构时。通过合理运用这一模式,可以显著提升代码的可读性和可维护性。

朗读
赞(0)
版权属于:

至尊技术网

本文链接:

https://www.zzwws.cn/archives/37815/(转载时请注明本文出处及文章链接)

评论 (0)

人生倒计时

今日已经过去小时
这周已经过去
本月已经过去
今年已经过去个月

最新回复

  1. 强强强
    2025-04-07
  2. jesse
    2025-01-16
  3. sowxkkxwwk
    2024-11-20
  4. zpzscldkea
    2024-11-20
  5. bruvoaaiju
    2024-11-14

标签云