前端设计模式——迭代器模式

124 阅读2分钟

迭代器模式是一种行为设计模式,它允许你在不暴露对象底层表示的情况下遍历对象的元素。迭代器模式通过提供一个迭代器来访问容器中的元素,使得容器可以提供多种遍历方式,同时可以隐藏容器内部的数据结构细节。

通常来说,迭代器模式包含两个主要的对象:迭代器和可迭代对象。可迭代对象是一个对象,它知道如何创建迭代器并且可以迭代它自己的元素。迭代器是一个对象,它知道如何遍历一个可迭代对象并且追踪当前遍历的位置。

迭代器模式可以在不改变可迭代对象代码的情况下,为其提供多种不同的遍历方式。此外,由于迭代器独立于容器,所以容器的结构可以更改而不会影响到遍历。迭代器模式还可以提供更简洁的遍历接口,因为它允许你使用通用的遍历方法来遍历不同类型的容器。

TypeScript 实现

在 TypeScript 中实现迭代器模式,可以定义一个接口 Iterator,它描述了迭代器应该实现的方法:

interface Iterator<T> {
  next(): {
    value: T;
    done: boolean;
  };
}

然后,我们可以使用该接口来定义一个集合的抽象类 Aggregate,其中包含一个方法 createIterator,它应该返回一个实现 Iterator 接口的迭代器对象:

abstract class Aggregate<T> {
  protected data: T[];

  constructor(data: T[]) {
    this.data = data;
  }

  public abstract createIterator(): Iterator<T>;
}

接下来,我们可以定义一个具体的迭代器对象 ArrayIterator,它实现了 Iterator 接口,并可以遍历一个数组:

class ArrayIterator<T> implements Iterator<T> {
  private index: number = 0;

  constructor(private data: T[]) {}

  public next() {
    if (this.index >= this.data.length) {
      return {
        value: null,
        done: true,
      };
    } else {
      return {
        value: this.data[this.index++],
        done: false,
      };
    }
  }
}

最后,我们可以定义一个具体的集合对象 ArrayAggregate,它继承了 Aggregate 抽象类,实现了 createIterator 方法,返回一个 ArrayIterator 迭代器对象:

class ArrayAggregate<T> extends Aggregate<T> {
  constructor(data: T[]) {
    super(data);
  }

  public createIterator(): Iterator<T> {
    return new ArrayIterator<T>(this.data);
  }
}

使用迭代器模式可以让集合对象和遍历算法解耦,提高代码的可维护性和可扩展性。

JavaScript 实现

在 JavaScript 中实现迭代器模式可以通过 Symbol.iterator 和 Generator 函数来实现。

Symbol.iterator 是一个内置的 Symbol 类型属性,它定义了对象的默认迭代器。在 ES6 中,所有的内置迭代器都是使用 Symbol.iterator 实现的。

Generator 函数是 ES6 中引入的一种新的函数类型,它通过 yield 语句实现了函数的暂停和恢复。

下面是一个使用 Generator 函数实现迭代器模式的示例:

function* createIterator(items) {
  for (let i = 0; i < items.length; i++) {
    yield items[i];
  }
}

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 }