什么是迭代
迭代就是从一个数据集合中,不断取出数据。
迭代器
ES中是一个对象,改对象有一个next方法,并且next方法中返回一个对象,这个对象有value和done属性。
const iterator = {
next(){
return {
value:xxx,// 下一个的值
done:Boolean, // 是否迭代完成
}
}
}
使用迭代器遍历数组
const arr = [1, 2, 3, 4, 5];
const iterator = {
i: 0,
next() {
const result = {
value: this.i >= arr.length ? '' : arr[this.i],
done: this.i >= arr.length,
}
this.i++;
return result;
}
}
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
/**
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: 4, done: false }
{ value: 5, done: false }
{ value: '', done: true }
{ value: '', done: true }
*/
迭代器创建器
function createIterator(arr) {
let i = 0;
const iterator = {
next() {
const result = {
value: i >= arr.length ? '' : arr[i],
done: i >= arr.length,
}
i++;
return result;
}
}
return iterator;
}
const arr1 = [1, 2, 34, 45, 100, 300, 400];
const arr2 = [2, 3, 4];
const iterator1 = createIterator(arr1);
let iter1 = iterator1.next();
while (!iter1.done) {
console.log(iter1.value);
iter1 = iterator1.next();
}
console.log('迭代完成');
使用迭代器获取斐波那契数列
function createFibonacciIterator() {
let i = 1,
prev2 = 1,
prev1 = 1,
value;
return {
next() {
if (i <= 2) {
value = 1;
} else {
value = prev2 + prev1;
}
const result = {
value,
done: false
}
let temp = prev1;
prev1 = value;
prev2 = temp;
i++;
return result;
}
}
}
const iterator = createFibonacciIterator();
console.log(iterator.next()); // 1
console.log(iterator.next()); // 1
console.log(iterator.next()); // 2
console.log(iterator.next()); // 3
console.log(iterator.next()); // 5
console.log(iterator.next()); // 8
console.log(iterator.next()); // 13
console.log(iterator.next()); // 21
console.log(iterator.next()); // 34
可迭代协议
如果一个对象具有知名符号属性Symbol.iterator,该属性返回一个迭代器创建函数,那么该对象就是可迭代的。
js中的数组就满足可迭代协议。
for of
for of循环可以用来遍历可迭代对象。
const obj = {
a: '1',
b: '2',
[Symbol.iterator]() {
const keys = Object.keys(this);
let i = 0;
return {
next: () => {
const value = {
propName: keys[i],
propValue: this[keys[i]]
}
const result = {
value,
done: i >= keys.length,
}
i++;
return result;
}
}
},
}
for (const item of obj) {
console.log(item);
// { propName: 'a', propValue: '1' }
// { propName: 'b', propValue: '2' }
}
展开运算符
利用展开运算符,可以将可迭代对象展开到数组中。
const a = [...obj];
console.log(a);
/**
* [
{ propName: 'a', propValue: '1' },
{ propName: 'b', propValue: '2' }
]
*
*/
生成器(generator)
生成器既是一个迭代器也是可迭代对象。
创建一个生成器
function *createGenerator(){
}
该函数就返回一个生成器。
yield
yield关键字只能在生成器创建函数中使用。
只有调用了next方法,生成器创建函数里面才会运行,调用几次next方法,就运行到相应的yield关键字后面,后面代码只有等下次调用next方法才会运行,当函数执行完成后,返回的生成器的状态done才会变为true。
next方法
生成器函数外部可以向 next 方法传递一个参数,这个参数会被当作上一个 yield 表达式的返回值,如果不传递任何参数,yield 表达式返回 undefined。
由于传递的参数被当作上一个yield表达式,所以第一次调用next传递的参数就不管用了。
return方法
return方法会提前结束迭代过程,如果有参数就作为迭代器对象的value值。
function *createGenerator() {
yield 1;
yield 3;
yield 4;
yield 5;
}
const generator = createGenerator();
const g = generator.next();
console.log(g);
console.log(generator.return());
console.log(generator.next());
// { value: 1, done: false }
// { value: undefined, done: true }
// { value: undefined, done: true }
catch
function *createGenerator() {
yield 1;
yield 3;
yield 4;
yield 5;
}
const generator = createGenerator();
const g = generator.next();
console.log(g);
console.log(generator.throw('error')); // 报错
console.log(generator.next());
// { value: 1, done: false }
// 报错
利用生成器创建迭代器
function *createIterator(arr){
for (const item of arr) {
yield item;
}
}
const arr = [1,2,3,4];
const iterator = createIterator(arr);
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
/* { value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: 4, done: false }
{ value: undefined, done: true }
{ value: undefined, done: true }
{ value: undefined, done: true } */
斐波拉契函数
function* createFibonacci() {
let prev2 = 1,
prev1 = 1,
n = 1;
while (true) {
if (n <= 2) {
yield 1;
} else {
const sum = prev2 + prev1;
yield sum;
prev1 = prev2;
prev2 = sum;
}
n++;
}
}
const fi = createFibonacci();
console.log(fi.next());
console.log(fi.next());
console.log(fi.next());
console.log(fi.next());
console.log(fi.next());
console.log(fi.next());
console.log(fi.next());
/* { value: 1, done: false }
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: 5, done: false }
{ value: 8, done: false }
{ value: 13, done: false } */
使用生成器模拟async/await
/**
* 模拟async/await
* @param {Generator} generatorFunc 生成器函数
*/
function runTask(generatorFunc) {
const generator = generatorFunc();
let result = generator.next(); // 开始迭代 {value: 1, done: false }
handleResult();
// 处理result
function handleResult() {
// 迭代结束
if (result.done) {
return;
}
// 迭代未结束 1.返回的是Promise,2.不是promise
if (typeof result.value.then === 'function') {
result.value.then(res => {
result = generator.next(res); // {value: undefined, done: true}
handleResult();
}, error => {
result = generator.next(error);
handleResult();
});
} else {
// next的参数会传给 yield表达式返回值
result = generator.next(result.value); // { value: promise, done: false }
// 继续处理后续
handleResult();
}
}
}
function* task() {
const a = yield 1;
console.log(a);
const res = yield new Promise((resolve, reject) => {
console.log('开始')
setTimeout(() => {
resolve('generator test')
}, 2000);
});
console.log(res);
}
runTask(task);
实现一个获取质数的函数(闭包的应用)
function isPrime(n) {
let flag = 0;
for (let i = 1; i <= n; i++) {
if (n % i === 0) {
flag++;
}
}
return flag === 2;
}
function getNextPrime() {
let i = 0;
return function () {
i++;
while (!isPrime(i)) {
i++;
}
return i;
}
}
const getPrime = getNextPrime();
console.log(getPrime());//2
console.log(getPrime());//3
console.log(getPrime());//5
console.log(getPrime());//7
console.log(getPrime());//11
console.log(getPrime());//13