什么是迭代器,生成器?有什么应用?

理解迭代器的概念

什么是迭代?

从一个数据集合中按照一定的顺序,不断取出数据的过程

迭代和遍历的区别?

迭代强调的是依次取数据,并不保证取多少,也不保证把所有的数据取完

遍历强调的是要把整个数据依次全部取出

例:在生活中,我们经常听到一个词叫产品迭代,一个产品有可能做到一半,公司倒闭导致产品无法继续迭代

什么是迭代器?

对迭代过程的封装,在不同的语言中有不同的表现形式,通常为对象

迭代模式

一种设计模式,用于统一迭代过程,并规范了迭代器规格:

  • 迭代器应该具有得到下一个数据的能力
  • 迭代器应该具有判断是否还有后续数据的能力

JS中的迭代器

JS规定,如果一个对象具有next方法,并且该方法返回一个对象,该对象的格式如下:

{
	value:,
	done: 是否迭代完成
}

则认为该对象是一个迭代器

数组迭代器

const arr = [1, 2, 3, 4, 5];
//迭代数组arr
const iterator = {
    i: 0, //当前的数组下标
    next() {
        var 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();
}

console.log("迭代完成")

这个iterator对象有next方法,并且返回一个包含value和down的对象,我们认为它是一个迭代器

什么时候适合使用迭代器?

当数据量无穷或者数据量很大的时候,适合使用迭代器
比如依次取菲波那切数列的值

function createFeiboIterator() {
let prev1 = 1,
    prev2 = 1, //当前位置的前1位和前2位
    n = 1; //当前是第几位

return {
    next() {
        let value;
        if (n <= 2) {
            value = 1;
        } else {
            value = prev1 + prev2;
        }
        const result = {
            value,
            done: false
        };
        prev2 = prev1;
        prev1 = result.value;
        n++;
        return result;
    }
}
}

const iterator = createFeiboIterator();

斐波那契数列无穷无尽,而且我们每次取得时候都是只关心下一个,所以适合迭代器

扫描二维码关注公众号,回复: 10973626 查看本文章

迭代器创建函数

当我们需要给两个数组分别创建迭代器的时候,那么会有冗余代码,这时候我们可以声明一个函数,函数返回一个迭代器,

const arr1 = [1, 2, 3, 4, 5];
const arr2 = [6, 7, 8, 9];

// 迭代器创建函数  iterator creator
function createIterator(arr) {
    let i = 0;//当前的数组下标
    return { 
        next() {
            var result = {
                value: arr[i],
                done: i >= arr.length
            }
            i++;
            return result;
        }
    }
}

const iter1 = createIterator(arr1);
const iter2 = createIterator(arr2);

可迭代协议 与 for-of 循环

可迭代协议

ES6规定,如果一个对象具有知名符号属性Symbol.iterator,并且属性值是一个迭代器创建函数,则该对象是可迭代的(iterable)

//可迭代对象
var obj = {
    a: 1,
    b: 2,
    [Symbol.iterator]() {
        const keys = Object.keys(this);
        let i = 0;
        return {
            next: () => {
                const propName = keys[i];
                const propValue = this[propName];
                const result = {
                    value: {
                        propName,
                        propValue
                    },
                    done: i >= keys.length
                }
                i++;
                return result;
            }
        }
    }
}

for (const item of obj) {
    console.log(item); // {propName:"a", propValue:1}
}

for-of 循环

for-of 循环用于遍历可迭代对象,格式如下

//迭代完成后循环结束
for(const item in iterable){
    //iterable:可迭代对象
    //item:每次迭代得到的数据
}

展开运算符与可迭代对象

展开运算符可以作用于可迭代对象,这样,就可以轻松的将可迭代对象转换为数组。

生成器

什么是生成器?

生成器是一个通过构造函数Generator创建的对象,生成器既是一个迭代器,同时又是一个可迭代对象

如何创建生成器?

生成器的创建,必须使用生成器函数(Generator Function)
如何书写一个生成器函数呢?

//这是一个生成器函数,该函数一定返回一个生成器
function* method(){

}

生成器函数内部是如何执行的?

生成器函数内部是为了给生成器的每次迭代提供的数据

每次调用生成器的next方法,将导致生成器函数运行到下一个yield关键字位置

yield是一个关键字,该关键字只能在生成器函数内部使用,表达“产生”一个迭代数据。

例:斐波那契数列生成器

function* feibo() {
    let last1 = 1,
        last2 = 1,
        i = 0;
    while (1) {
        if (i <= 1) {
            yield 1
        } else {
            let result = last1 + last2;
            yield result;
            last1 = last2;
            last2 = result
        }
        i ++
    }
}
let generator = feibo();
console.log(generator.next())

next的参数和return

生成器的可迭代对象的next方法可接受一个参数,这个参数会赋值给yield表达式

function *test() {
   let v1 = yield 1;
    console.log(v1);
    let v2 = yield 2 + v1;
    console.log(v2);
    return 99
}
let generator = test();
console.log(generator.next())

有哪些需要注意的细节?

1). 生成器函数可以有返回值,返回值出现在第一次done为true时的value属性中
2). 调用生成器的next方法时,可以传递参数,传递的参数会交给yield表达式的返回值
3). 第一次调用next方法时,传参没有任何意义
4). 在生成器函数内部,可以调用其他生成器函数,但是要注意加上*号

生成器的其他API

  • return方法:调用该方法,可以提前结束生成器函数,从而提前让整个迭代过程结束
  • throw方法:调用该方法,可以在生成器中产生一个错误,并提前结束迭代过程
function* feibo() {
    let last1 = 1,
        last2 = 1,
        i = 0;
    while (1) {
        if (i <= 1) {
            yield 1
        } else {
            let result = last1 + last2;
            yield result;
            last1 = last2;
            last2 = result
        }
        i ++
    }
}
let generator = feibo();
console.log(generator.next())
console.log(generator.return(100)) // {value: 100, down: true}
function* feibo() {
    let last1 = 1,
        last2 = 1,
        i = 0;
    while (1) {
        if (i <= 1) {
            yield 1
        } else {
            let result = last1 + last2;
            yield result;
            last1 = last2;
            last2 = result
        }
        i ++
    }
}
let generator = feibo();
console.log(generator.next())
console.log(generator.throw(100)) // {value: 100, down: true}
console.log(generator.next()) // {value: undefined, done: true}

生成器的应用

生成器在react源码中有大量的使用,生成器弥补了es6还没有async和await的缺陷
可以使用使用生成器完成优雅的异步调用

function* task() {
   const resp = yield fetch("https://developer.duyiedu.com/edu/groupChat/getMsgList")
    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 (result.value instanceof Promise) {
            //1. 迭代的数据是一个Promise
            //等待Promise完成后,再进行下一次迭代
            result.value.then(data => {
                result = generator.next(data)
                handleResult();
            })
        } else {
            //2. 迭代的数据是其他数据,直接进行下一次迭代
            result = generator.next(result.value)
            handleResult();
        }
    }
}
发布了10 篇原创文章 · 获赞 97 · 访问量 4944

猜你喜欢

转载自blog.csdn.net/qq_45516476/article/details/105462254