目录
迭代的理解
把一堆数据按照一定的顺序拿出来的过程。再简单点就是从一堆东西中,先拿一个,再拿一个。
迭代和遍历的区分
迭代强调是:依次取数据,取多少,取不取完都不知道,取一个算一个。
遍历强调的是:要取完,即完整性。
产品迭代:这个产品最终是什么样的是不知道的,但是可以去做这产品,在过程中不断迭代更新。
迭代器
对迭代过程的封装。帮我们去拿数据的一个东西。通常表示为对象。
迭代模式
规定迭代器的功能。
- 迭代器应该有得到下一个数据的能力。
- 迭代器应该具有判断后面还有没有数据的能力。
js中的迭代器
如果一个对象具有next方法, 并且这个方法返回一个对象,对象的格式如下:
{ value: 值,done: 是否迭代完成}
代码如下:
const obj = {
next(){
return {
value:"",
done:boolean
}
}
}
那么obj就是一个迭代器。
迭代数组
const arr = [1, 2, 3, 4, 5];
const iterator = {
i: 0,
next() {
const result = {
value: arr[this.i],
done: this.i >= arr.length
}
this.i++;
return result;
}
}
let data = iterator.next();
while (!data.done) {
console.log(data.value);
data = iterator.next();
}
迭代器创建函数
function getIterator(arr) {
let i = 0;
return {
next() {
const result = {
value: arr[i],
done: i >= arr.length
}
i++;
return result;
}
}
}
斐波拉契数组
function createFriboIterator() {
let temp1 = 1,
temp2 = 1, //当前位的前两位
n = 1; //当前是第几位
return {
next() {
if (n <= 2) {
value = 1
} else {
value = temp1 + temp2;
}
const result = {
value,
done: false
}
temp1 = temp2;
temp2 = result.value;
n++;
return result;
}
}
}
const feibo = createFriboIterator();
可迭代对象
如果一个对象具有一个Symbol.iterator的属性名,其值为一个迭代器创建函数,那么这个对象就是可迭代对象。比如:
const obj = {
[Symbol.iterator]:function(){
return {
next(){
return {
value:""
done:""
}
}
}
}
}
es6中数组是一个可迭代对象
const arr = [1,2,3,4,5];
const iterator = arr[Symbol.iterator]();
- 浏览器中将dom对象也封装成可迭代对象
遍历可迭代对象
const arr = [1,2,3,4,5];
const iterator = arr[Symbol.iterator]();
let item = iterator.next();
while(!item.done){
console.log(item.value);
item = iterator.next();
}
es6 for-of循环
for-of循环遍历可迭代对象,格式:
for(const item of iterable){
item://每次迭代得到的对象
iterable://可迭代对象
}
const arr = [1,2,3,4,5];
for(const item of arr){
console.log(item);
}
等价于
const arr = [1,2,3,4,5];
const iterator = arr[Symbol.iterator]();
const item = iterator.next();
while(!item.done){
console.log(itme.value);
item = itertator.next();
}
自定义可迭代对象
const obj = {
a: 1,
b: 2,
[Symbol.iterator]() {
const arr = Object.keys(this);
let i = 0;
return {
next: () => {
const result = {
value: {
propName: arr[i],
propValue: this[arr[i]]
},
done: i >= arr.length
}
i++;
return result;
}
}
}
}
for (const iterator of obj) {
console.log(iterator); //
}
展开运算符与可迭代对象
展开运算符可以作用于可迭代对象。这样就可以将可迭代对象转化为数组。
const obj = {
a: 1,
b: 2,
[Symbol.iterator]() {
const arr = Object.keys(this);
let i = 0;
return {
next: () => {
const result = {
value: {
propName: arr[i],
propValue: this[arr[i]]
},
done: i >= arr.length
}
i++;
return result;
}
}
}
}
const arr = [...obj];
console.log(arr);
function test(a, b) {
console.log(a);
console.log(b);
}
// 第一次迭代的结果放在第一个参数,第二次迭代的结果放在第二个参数
test(...obj);
生成器(generator)
生成器的出现是为了解决迭代器的编写复杂
生成器是一个迭代器,又是一个可迭代对象。
书写生成器
//这是一个生成器函数,该函数一定返回一个生成器。
function *method(){
//这里面的代码要生成器迭代后才能运行,调用methed()生成器函数,只是得到一个生成器。
//yield关键字 只能在生成器函数里面使用,给生成器提供迭代数据
//生成器调用一次next()方法进行一次迭代,拿到yield关键字后面的数据
}
生成器例子
function *test(){
console.log('第一次运行');
yield 1;
console.log('第二次运行');
yield 2;
console.log('第三次运行');
}
//调用一个生成器函数,得到一个生成器。这里调用函数test不会运行函数体里面的语句。
const generator = test();
//生成器进行迭代,运行到yield关键字,拿到迭代的数据
console.log(generator.next()); //第一次运行 {value: 1, done: false}
console.log(generator.next()); // 第二次运行 {value: 2, done: false}
console.log(generator.next()); // 第三次运行 {value: undefined, done: true}
利用生成器改造之前的迭代器
- 循环数组
const arr = [1,2,3,4,5];
function *createIterator(arr){
for (const item of arr) {
yield item;
}
}
const generator = createIterator(arr);
let item = generator.next();
while(!item.done){
console.log(item);
item = generator.next();
}
- 斐波拉契函数
function* createFeibo() {
let temp1 = 1,
temp2 = 1,
n = 1;
while(true){
if(n <= 2){
yield 1;
} else {
let newValue = temp1 + temp2;
yield newValue;
temp1 = temp2;
temp2 = newValue;
}
n++;
}
}
const feibo = createFeibo();
生成器函数需要注意的几个点
- 函数的返回值,出现在第一次done为true的value里面
function *test(){
console.log('第一次运行');
yield 1;
console.log('第二次运行');
yield 2;
console.log('第三次运行');
return 100;
}
const generator = test();
console.log(generator.next()); //第一次运行 {value: 1, done: false}
console.log(generator.next()); // 第二次运行 {value: 2, done: false}
console.log(generator.next()); // 第三次运行 {value: 100, done: true}
console.log(generator.next()); // {value: undefined, done: true}
- 生成器调用next方法时,可以传递参数,参数会交给yield表达式的返回值
function *test(){
let info = yield 1;
console.log(info);
info = yield 2 + info;
console.log(info);
}
const generator = test();
console.log(generator.next()); //{value:1,done:false}
console.log(generator.next(10)); // 10 {value:12,done:false}
console.log(generator.next()); // undefined {value:undefined,done:true}
分析:
3. 第一次通过next传递参数没有意义。没有用。
4. 生成器其它api
- return方法:调用该方法,提前结束生成器函数,提前结束迭代过程。
function *test(){
yield 1;
yield 2;
yield 3;
}
const generator = test();
console.log(generator.next()); // {value:1,done:false}
console.log(generator.return());//{value:undefined,done:true}
console.log(generator.next()); // {value:undefined,done:true}
function *test(){
yield 1;
yield 2;
yield 3;
}
const generator = test();
console.log(generator.next()); // {value:1,done:false}
console.log(generator.return(100));//{value:100,done:true}
console.log(generator.next()); // {value:undefined,done:true}
- throw方法:调用该方法,可以在生成器中产生一个错误。
- 在生成器函数内部,可以调用其它生成器函数,但是要加上*号
function* test1(){
yield 'a';
yield 'b';
}
function* test() {
//得到是是生成器,没有迭代不会运行
test1();
yield 1;
yield 2;
yield 3;
}
const generator = test();
console.log(generator.next()); //{value:1,done:false}
function* test1(){
yield 'a';
yield 'b';
}
function* test() {
// value值为test1这个生成器
yield test1();
yield 1;
yield 2;
yield 3;
}
const generator = test();
console.log(generator.next()); //{value:test1,done:false}
function* test1(){
yield 'a';
yield 'b';
}
function* test() {
// 正确的调用
yield *test1();
yield 1;
yield 2;
yield 3;
}
const generator = test();
console.log(generator.next()); //{value:'a',done:false}
生成器的应用(react中会用)
promise出来后,async await还没出来,promise是es6.async await是es7
用promise来写还是有点繁琐,然后生成器是es6的,所以生成器这里可以简化promise。模拟async和await
function* task() {
const d = yield 1;
console.log(d)
// //d : 1
const resp = yield fetch("url")
const result = yield resp.json();
console.log(result);
}
run(task)
function run(generatorFunc) {
const generator = generatorFunc();
let result = generator.next(); //启动任务(开始迭代), 得到迭代数据
handleResult();
//对result进行处理
function handleResult() {
if (result.done) {
return; //迭代完成,不处理
}
//迭代没有完成,分为两种情况
//1. 迭代的数据是一个Promise
//2. 迭代的数据是其他数据
if (typeof result.value.then === "function") {
//1. 迭代的数据是一个Promise
//等待Promise完成后,再进行下一次迭代
result.value.then(data => {
result = generator.next(data)
handleResult();
})
} else {
//2. 迭代的数据是其他数据,直接进行下一次迭代
result = generator.next(result.value)
handleResult();
}
}
}