迭代器
首先先来理解一下什么是迭代器,从一个数据的集合中,不断地拿取出数据的过程。但是遍历似乎也是这样的。同时js中规定如果一个对象有next方法,并且返回一个{value: 值, done: 是否迭代完成}格式的代码,那么就是一个迭代器。同时迭代器还要有能力得到下一个数据,并且判断后面是否还有数据。
所以迭代与遍历的区别 迭代强调的是依次拿取数据,但是不强调要拿取的数据的数量 遍历强调的是拿取限定条件里面的所有数据
可能大家还是有点不太明白的,这里通过一段代码来演示,并且我们自己写一个简单的迭代器
const arr = ['a','b','c','d'];
//首先通过for循环来遍历数组集合,那么就会根据我们的要求,获取要求内的全部数据
for (let j = 0; j < 2; j++) console.log(brr[j]);
//我们来看迭代数据
//首先写一个基本的迭代器
var iterator = {
i: 0,
next() {
return {
value: brr[this.i++],
done: this.i > brr.length,
};
},
};
console.log(iterator.next().value);//拿取到数据
在上面的代码中,第一个例子是通过遍历来拿取数据,这里会拿取到条件里所有的数据 。第二个是通过迭代器拿取数据,我们可以把对于获取数据的要求都写在迭代器中,让他去处理,而我们自己获取数据的时候,就不用考虑数组的长度等等。
这里我们来实践一下迭代器的使用场景,并且通过需求来写一个迭代器:依次获取n位的斐波拉契数列
//这里我们先不考虑使用函数然后递归来完成
//要依次拿到n位的数据,首先这里如果用数组来一次存储数据的话,因为n的不确定性,如果设置数组过长,浪费空间,过短的话,又得不到n的数据。
//因此迭代器就特别适合于这种,数据量特别大,或者无限长的数据
//设置来编辑一个迭代器,这里用函数来封装,通过迭代器,我们可以无限的获取到数据
function createFeiboIterator() {
let pre1 = 1,
pre2 = 1,
n = 1;
return {
next() {
let value = 0;
if (n <= 2) value = 1;
else value = pre1 + pre2;
let result = {
value,
done: false,
};
pre1 = pre2;
pre2 = result.value;
n++;
return result;
},
};
}
let a = createFeiboIterator();
console.log(a.next());
console.log(a.next());
可迭代协议
可迭代协议:再es6里面规定,如果一个对象具有知名符号Symbol.iterator,并且也是一个迭代器创建函数,那么这个对象就是一个可迭代对象。在es6后数组,类数组都已经是可迭代对象的了。
这是在控制台里面打印的一个普通数组
尽然数组是可迭代对象,并且有迭代函数,因此当然可以通过迭代器来打印了
const arr = [1,2,3,4,5];
let iterator = arr[Symbol.iterator]();
let res = iterator.next();
while(!res.done){
console.log(res.value);
res = iterator.next();
}
for of
for of就是专门用来循环可迭代对象的,因此for of 也可以循环我们自己写的迭代对象
let obj = {
'a':'aa',
'b':'bb',
'c':'cc',
'd':'dd',
[Symbol.iterator] (){
const keys = Object.keys(this);
let i = 0;
return {
next(){
let result= {
value: `${keys[i]}->${obj[keys[i]]}`,
done: i>=keys.length
}
i++;
return result;
}
}
}
}
for(const prop of obj) {
console.log(prop);
}
生成器
js中的生成器,是通过Generator构造函数,创建的对象。他最本质的作用就是方便我们来编写迭代器。
首先看一下下如何编写生成器//这就是一个简单的生成器函数,调用他一定会的得到一个生成器的
function *createIterator(){}
const generator = createIterator();
这里我们在编写一段代码来对比下,自己编写迭代器与使用生成器的区别
//需要将obj对象的value进行迭代
let obj = {
0: "a",
1: "b",
2: "c",
};
//1,我们自己编写一个迭代器来完成
let obj = {
0: "a",
1: "b",
2: "c",
[Symbol.iterator]() {
const keys = Object.keys(this);
let index = 0;
return {
next: () => {
let result = {
value: this[keys[index]],
done: index >= keys.length,
};
index++;
return result;
},
};
},
};
//进行输出
let iterator = obj[Symbol.iterator]();
console.log(iterator.next());
//2,通过生成器的方式来实现
let obj = {
0: "a",
1: "b",
2: "c",
};
function* createIterator(param) {
const keys = Object.keys(param);
for (const prop of keys) {
yield param[prop];
}
}
const generator = createIterator(obj);
console.log(generator.next());
是不是通过上面的代码,瞬间感觉到用生成器来来实现要简单很多的,这还是我们在处理简单的需求的基础上。
生成器的语法
-
生成器内部的运行
//在生成器里面,具有一个关键字yield,这个关键字的作用就是将后面的数据传递给我们每次通过next迭代的value值 //同时我们每次调用next方法,都会运行生成器函数,运行到下一个yield关键字的位置。 function *createIterator(){ yield 1; yield 2; yield 3; } const generator = createIterator(); ``` -
生成器传参
//首先第一次next,传参无效,因为没有参数接收的。 //后面的传参,都会是yield关键字的返回值,拿到参数后,可以进行使用 function* createIterator() { let params = yield 1; yield 2 + params; yield 3; } const generator = createIterator(); console.log(generator.next()); console.log(generator.next("第二次运行"));