迭代器(Iterator)
迭代器就是一种机制,一种接口,就是给各种不同的数据结构提供访问机制。一种包含数据的结构实现了迭代器接口就可以通过for…of遍历。
Iterator的遍历过程如下:
1.会创建一个指针对象,指向此数据结构的起始位置,遍历器对象本身就是一个指
针对象。
2.它就是去调用Iterator实现的next()方法,第一次调用,就把指针指向数据的
第一个成员,且返回。第二次调用就指向第二个成员,直到最后。
每次返回的是一个对象,{value:成员数据,done:布尔值},value就是该数据结构的成员数据,done是指遍历是否结束。
下面用函数模拟next方法:
{
//函数实现一个next方法。
function makeItrator(arr) {
let indexnext = 0;
return {
next: function () {
console.log(indexnext);//调用4次:一次输出:0 1 2 3
return indexnext < arr.length ? { value: arr[indexnext++], dome: false } : { value: undefined, dome: true };
}
}
};
let it = makeItrator([1, 2, 3]);//这里必须用一个原始值来指向这个函数。
console.log(makeItrator([1, 2, 3]).next == makeItrator([1, 2, 3]).next);//输出false,因为直接电用函数名,调用一次就创建一个新的函数。
console.log(it.next == it.next);//返回true,因为it就指向一个函数makeItrator
console.log(it.next());//第一次调用结束的时候,it保存的这个函数里面的indexnext变成了1,再下一次调用的时候,还是这个函数
console.log(it.next());//第二次掉调用的时候,还是那个函数,但是里面的indexnext已经变成了1。
console.log(it.next());//{ value: 3, dome: false }
console.log(it.next());//{ value: undefined, dome: true }
}
上面就模拟了next方法,调用一次就修改indexnext这个索引,直到结束,然后返回done:true。
迭代器的用途:就是对各种包含数据的结构实现可遍历。
用一个例子:实现用for…of对普通对象的遍历,如果对象没有实现迭代器接口时不能使用for…of遍历的。(这只是举一个例子,这样做肯定没有意义的,以为for…in可实现对象的遍历。)
代码:
{
let obj = {
name: "Tom",
age: 18,
sex: "男",
city: "成都",
high: "180cm",
[Symbol.iterator]() {
let arrName = Object.keys(this);
let that = this;
let index = 0;
return {
next: function () {
return index < arrName.length ? { value: [arrName[index], that[arrName[index++]]], done: false } : { done: true }
}
}
}
};
for (let i of obj) {
console.log(i);
}
//输出结果:
[ 'name', 'Tom' ]
[ 'age', 18 ]
[ 'sex', '男' ]
[ 'city', '成都' ]
[ 'high', '180cm' ]
}
[Symbol.iterator]就是一个属性,ES6中规定Iterator接口默认部署到该属性上。也可以说是该数据结构一旦有这个属性,就说明是可迭代的(但是函数中要具体实现)。
可以看出迭代器的用途就是:实现数据结构的可遍历。
生成器函数Generator
Generator就是一个普通dingy的函数,它的特征:1.function与函数名之间一个*(星号)标识。2.函数体内部使用yield语句定义不同的内部状态。
yield:函数中遇到yield,就会把紧跟yield后面的表达式进行执行再返回,下一句语句就会暂停执行,只有下一次调用的时候才会执行下一句。
例如:
{
function* generator() {
yield 1;
yield 2;
return undefined;
};
let ge = generator();//该函数会返回一个迭代器对象,所以就直接调用next()
console.log(ge.next());// { value: 1, done: false }
console.log(ge.next());// { value: 2, done: false }
console.log(ge.next());// { value: undefined, done: true }
}
生成器和迭代器的结合使用,会使得编程变得更加的方便,简洁。
例如:
{
let obj = {
name: "Tom",
age: 18,
sex: "男",
city: "成都",
high: "180cm",
[Symbol.iterator]: function* () {
for (let i in this) {
yield [i,this[i]]
}
}
};
// let ge = obj[Symbol.iterator]()
for (let i of obj) {
console.log(i);
}
//输出结果:
[ 'name', 'Tom' ]
[ 'age', 18 ]
[ 'sex', '男' ]
[ 'city', '成都' ]
[ 'high', '180cm' ]
}
实例:利用类和生成器函数实现:输出小于100的斐波那契数列。
{
class Fib {
constructor(max) {
this.value = max;
};
[Symbol.iterator] = function*() {
let f1 = 0;
let f2 = 1;
while (true) {
var curent = f1;
yield f1
f1 = f2;
f2 = curent + f2;
if (f1 > this.value) {
return
}
}
}
}
let fib = new Fib(100);
for (let i of fib) {
console.log(i);
}
}
打印结果: