原创 TypeScript入门教程 之 迭代器
Iterator
Iterator本身不是TypeScript或ES6功能,Iterator是面向对象的编程语言所通用的行为设计模式。通常,它是一个实现以下接口的对象:
interface Iterator<T> {
next(value?: any): IteratorResult<T>;
return?(value?: any): IteratorResult<T>;
throw?(e?: any): IteratorResult<T>;
}
(有关该<T>
符号的更多信息,请参见后面的内容。)
此接口允许从属于该对象的某个集合或序列中检索值。
IteratorResult
IteratorResult
是一个简单的value
+ done
对:
interface IteratorResult<T> {
done: boolean;
value: T;
}
Iterator接口使用示例
想象有一个框架的对象,其中包括该框架所组成的组件的列表。使用Iterator接口,可以从该框架对象中检索组件,如下所示:
class Component {
constructor (public name: string) {}
}
class Frame implements Iterator<Component> {
private pointer = 0;
constructor(public name: string, public components: Component[]) {}
public next(): IteratorResult<Component> {
if (this.pointer < this.components.length) {
return {
done: false,
value: this.components[this.pointer++]
}
} else {
return {
done: true,
value: null
}
}
}
}
let frame = new Frame("Door", [new Component("top"), new Component("bottom"), new Component("left"), new Component("right")]);
let iteratorResult1 = frame.next(); //{ done: false, value: Component { name: 'top' } }
let iteratorResult2 = frame.next(); //{ done: false, value: Component { name: 'bottom' } }
let iteratorResult3 = frame.next(); //{ done: false, value: Component { name: 'left' } }
let iteratorResult4 = frame.next(); //{ done: false, value: Component { name: 'right' } }
let iteratorResult5 = frame.next(); //{ done: true, value: null }
//It is possible to access the value of iterator result via the value property:
let component = iteratorResult1.value; //Component { name: 'top' }
再次。Iterator本身不是TypeScript功能,该代码无需显式实现Iterator和IteratorResult接口就可以工作。但是,使用这些通用的ES6 接口来保持代码一致性非常有帮助。
好的,很好,但是可能会有所帮助。ES6定义了可迭代协议 ,symbol
如果实现了可迭代接口,则该协议包括[Symbol.iterator] :
//...
class Frame implements Iterable<Component> {
constructor(public name: string, public components: Component[]) {}
[Symbol.iterator]() {
let pointer = 0;
let components = this.components;
return {
next(): IteratorResult<Component> {
if (pointer < components.length) {
return {
done: false,
value: components[pointer++]
}
} else {
return {
done: true,
value: null
}
}
}
}
}
}
let frame = new Frame("Door", [new Component("top"), new Component("bottom"), new Component("left"), new Component("right")]);
for (let cmp of frame) {
console.log(cmp);
}
不幸的是frame.next()
,这种模式无法使用,而且看起来有些笨拙。IterableIterator界面可以解救!
//...
class Frame implements IterableIterator<Component> {
private pointer = 0;
constructor(public name: string, public components: Component[]) {}
public next(): IteratorResult<Component> {
if (this.pointer < this.components.length) {
return {
done: false,
value: this.components[this.pointer++]
}
} else {
return {
done: true,
value: null
}
}
}
[Symbol.iterator](): IterableIterator<Component> {
return this;
}
}
//...
无论frame.next()
和for
周期,现在做工精细用IterableIterator接口。
迭代器不必迭代有限的值。典型的例子是斐波那契数列:
class Fib implements IterableIterator<number> {
protected fn1 = 0;
protected fn2 = 1;
constructor(protected maxValue?: number) {}
public next(): IteratorResult<number> {
var current = this.fn1;
this.fn1 = this.fn2;
this.fn2 = current + this.fn1;
if (this.maxValue != null && current >= this.maxValue) {
return {
done: true,
value: null
}
}
return {
done: false,
value: current
}
}
[Symbol.iterator](): IterableIterator<number> {
return this;
}
}
let fib = new Fib();
fib.next() //{ done: false, value: 0 }
fib.next() //{ done: false, value: 1 }
fib.next() //{ done: false, value: 1 }
fib.next() //{ done: false, value: 2 }
fib.next() //{ done: false, value: 3 }
fib.next() //{ done: false, value: 5 }
let fibMax50 = new Fib(50);
console.log(Array.from(fibMax50)); // [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
let fibMax21 = new Fib(21);
for(let num of fibMax21) {
console.log(num); //Prints fibonacci sequence 0 to 21
}
使用迭代器为ES5目标构建代码
上面的代码示例需要ES6目标。但是,如果目标JS引擎支持,它也可以与ES5目标一起使用Symbol.iterator
。这可以通过使用带有ES5目标的ES6库(将es6.d.ts添加到您的项目中)进行编译来实现。编译后的代码应在节点4 +,Google Chrome和其他一些浏览器中运行。
翻译来源:https://gitee.com/yunwisdoms/typescript-book/blob/master/docs/iterators.md