美文网首页程序员Web前端之路让前端飞
ES6 中 iterator 和 generator(1)

ES6 中 iterator 和 generator(1)

作者: zidea | 来源:发表于2019-05-21 06:29 被阅读24次
    javascript

    在开始分享之前先介绍一个好用 visual studio code 的插件 Quokka.js 安装后会给我们带来许多遍历,我们无需执行文件,在开发过程中就可以实时地看到结果。提供两个版本一个是免费 community 和一个收费 pro 版本。有钱可以支持一下,是一个提高开发效率的好工具。

    安装后只要 shift+command+p 调用命令 Quockka.js:start on current file 就可以在开发过程实时地观察到运行结果。当然提供许多其他的命令大家感兴趣可以看一下官方文档

    图1

    遍历

    const tuts = [
        'angular basic',
        'reac basic',
        'vue basic',
    ];
    
    for(const tut of tuts){
        
    }
    

    我们通常会这样遍历集合,来获取集合每一个元素。

    迭代器

    const iterator = tuts[Symbol.iterator]()
    iterator{[Iterator]}
    
    for(const tut of tuts){
        tut;
    }
    

    通过方法集合 tuts[Symbol.iterator]() 的方法,返回返回一个该集合的迭代器供我们使用,这里有一个相对不好理解 Symbol ,其实 Symbol (符号)是一个 ES6 的新特性表示唯一的属性,当我们在 javascript 中定义一个接口类,其中提供一个需要实现该接口的类需要实现的方法就可以通过 Symbol 来定义,这样可以避免冲突。

    const iterator = tuts[Symbol.iterator]()
    

    每一个集合都有一个迭代器 iterator,获取 iterator 迭代器之后通过调用iterator.next()方法我们就可以得到一个对象

    { value: 'angular basic', done: false }
    

    这个对象包含两个属性分别是 value 和 done,value 是集合中值而 done 表示集合遍历是否结束,当集合没有更多的值可取,done 属性为 true ,value 为 undefined。

    一个实例

    首先引入一个可以生产随机数的库 random-number

    const randomNumber = require('random-number');
    

    使用 random-number 创建随机数很简单,给出一个取值范围和数据类型就可以得到随机数

    randomNumber({
        min:0,
        max:10,
        integer:true
    })
    

    然后就可以创建是可以生产集合中随机索引的方法 randomItem,用于为传入集合中生产一个随机的索引。

    const randomNumber = require('random-number');
    
    function randomItem(array){
        const randomIndex =  randomNumber({
            min:0,
            max:array.length - 1,
            integer:true
        })
    
        return array[randomIndex]
    }
    
    module.exports = randomItem;
    

    创建一个课程生产器用于随机随机生产课程。

    
    const randomItem = require('./random-item')
    
    const makeTut = () =>{
        const tutSizes = ['big','medium','tiny']
        const tutCategory = ['java','javascript','golang']
        return randomItem(tutSizes) + ' ' + randomItem(tutCategory)
             + ' ' + 'tut'
    }
    
    module.exports = makeTut;
    

    然后就可以测试一下通过调用 makeTut() 然后就生产课程对象

    const makeTut = require('./make-tut');
    
    console.log(makeTut());
    console.log(makeTut());
    console.log(makeTut());
    

    自定义生成器

    我们知道一个对象只要实现了Symbol.iterator] 就可以是一个迭代器,我们就可以 for 循环来遍历对象 tutList。

    const tutList = {
        [Symbol.iterator]: ()=>{
            return {
                next:()=>{
                    const enoughTut = Math.random() > 0.75
                    if(!enoughTut){
                        return {
                            value:makeTut(),
                            done:false
                        }
                    }
                    return {done:true}
                }
            }
        }
    }
    
    for(const tut of tutList){
        console.log(tut);
    }
    
    medium golang tut
    tiny javascript tut
    medium javascript tut
    big javascript tut
    medium java tut
    big java tut
    
    javascript

    生产器

    其实生成器(generator)就是方便生成迭代器(iterator)的语法糖。
    生产器函数与普通函数不同,他神奇之处是一个可暂停的函数,这个函数会根据用户调用而逐步执行。既然他与不同函数不同为了区分,需要定义时候在 function 后面添加一个星号以便区别。这个函数会返回一个迭代器(iterator),函数内部通过 yield 来返回用于作为 iterator.next() 执行时返回的值。

    function* someTuts(){
        yield 'angularjs basic tut';
        yield 'react basic tut';
        yield 'vuejs basic tut';
    }
    
    
    const iterator = someTuts();
    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());
    console.log(iterator.next());
    
    { value: 'angularjs basic tut', done: false }
    { value: 'react basic tut', done: false }
    { value: 'vuejs basic tut', done: false }
    { value: undefined, done: true }
    { value: undefined, done: true }
    { value: undefined, done: true }
    { value: undefined, done: true }
    { value: undefined, done: true }
    

    如果 someTuts return 结束后在 return 之后的元素是无法通过迭代取到的。而且 done 值设置为 true 表示没有更多的值可取。

    function* someTuts(){
        yield 'angularjs basic tut';
        yield 'react basic tut';
        return;
        yield 'vuejs basic tut';
    }
    
    { value: 'angularjs basic tut', done: false }
    { value: 'react basic tut', done: false }
    { value: undefined, done: true }
    { value: undefined, done: true }
    { value: undefined, done: true }
    { value: undefined, done: true }
    { value: undefined, done: true }
    { value: undefined, done: true }
    

    如果返回值不是 undefined 而是实际的值,可以返回该值,但是 done 值也就是 true。generator 是随着 iterator.next() 的调用而逐步执行所以说 generator 是一个可暂停的函数。

    function* someTuts(){
        yield 'angularjs basic tut';
        yield 'react basic tut';
        return 'golang basic tut';
        yield 'vuejs basic tut';
    }
    
    { value: 'angularjs basic tut', done: false }
    { value: 'react basic tut', done: false }
    { value: 'golang basic tut', done: true }
    { value: undefined, done: true }
    
    function* someTuts(){
        while(true){
            const enoughTut = Math.random() > 0.75
            if(enoughTut) return;
            yield makeTut();
        }
    }
    
    
    const iterator = someTuts();
    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());
    console.log(iterator.next());
    
    { value: 'tiny javascript tut', done: false }
    { value: 'tiny javascript tut', done: false }
    { value: 'medium javascript tut', done: false }
    { value: undefined, done: true }
    { value: undefined, done: true }
    { value: undefined, done: true }
    { value: undefined, done: true }
    { value: undefined, done: true }
    

    我们可以通过代码来简单地实现一个生成器 generator.

    function someTuts(){
        let iterations = -1;
        const iterator = {
            next:()=>{
                return { value: 'angular basic tut', done:true}
            }
        }
    
        return iterator;
    }
    
    function someTuts(){
        let iterations = -1;
        const iterator = {
            next:()=>{
                iterations++
                if(iterations === 0){
                    return { value: 'angular basic tut', done:false}
                }else if(iterations === 1){
                    return { value: 'react basic tut', done:false}
                }else{
                    return {done:true}
                }
            }
        }
    
        return iterator;
    }
    

    通过简单实现生产器,大家不难发现在生成器中是有一个迭代器,迭代器具体控制如何迭代集合。

    javascript

    相关文章

      网友评论

        本文标题:ES6 中 iterator 和 generator(1)

        本文链接:https://www.haomeiwen.com/subject/epahzqtx.html