ES6-迭代器、生成器

迭代器

迭代器(lterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署lterator接口,就可以完成遍历操作。

ES6迭代器的使用

  • ES6创造了一种新的遍历命令for...of循环,lterator接口主要供 for...of消费
  • 原生具备iterator接口的数据(可用for of遍历):
    • Array
    • Arguments
    • Set
    • Map
    • String
    • TypedArray
    • NodeList
      具备iterator接口就是指具有 Symbol.iterator这个属性

eg:

        const xiyou =['唐僧','孙悟空','猪八戒','沙僧']

        // for ... of 遍历数组:保存的是值
        for(let v of xiyou){
    
    
            console.log(v)
        }
        
        // for ... in 遍历数组:保存的是下标
        for(let v in xiyou){
    
    
            console.log(v)
        }

        console.log(xiyou)

输出:
在这里插入图片描述
在这里插入图片描述

ES6迭代器的原理

数组之所以能够使用迭代器遍历是因为数组中有 Symbol.iterator这个属性,他的值是一个函数。
获取该函数

        const xiyou =['唐僧','孙悟空','猪八戒','沙僧']
        let iterator = xiyou[Symbol.iterator]()
        console.log(iterator)

在这里插入图片描述
有next方法。

迭代器工作原理:

  • 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
  • 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
  • 每调用next方法返回一个包含value和 done属性的对象

即迭代器的实现原理就是:

        const xiyou =['唐僧','孙悟空','猪八戒','沙僧']
        let iterator = xiyou[Symbol.iterator]()
        console.log(iterator.next())
        console.log(iterator.next())
        console.log(iterator.next())
        console.log(iterator.next())
        console.log(iterator.next())

输出:
在这里插入图片描述

迭代器的应用——自定义遍历数据

如果想要便利的对象没有Symbol.iterator属性,可以自定义该属性进行遍历
eg:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>

    <script>
    const banji = {
      
      
        name:'终极一班',
        stus:[
            'xiaoming',
            'xiaohong',
            'xiaoli',
            'xiaozhang'
        ],
        [Symbol.iterator](){
      
      
            // 索引变量
            let index = 0;
            let _this = this;
            return {
      
      
            //按照迭代器的遍历规则写出next函数
                next:function(){
      
      
                    if(index <_this.stus.length){
      
      
                        const result = {
      
      value:_this.stus[index],done:false}
                        index++;
                        return result
                    }else{
      
      
                        return {
      
      value:undefined,done:true}
                    }
                }
            }
        }
    }

    // 使用for of 遍历对象,且结果是stus的内容
    for( let v of banji){
      
      
        console.log(v)
    }

    </script>    
</body>
</html>

在这里插入图片描述

生成器

生成器是一个函数,生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。
之前实现异步编程使用的都是回调函数(回调函数:我们编写的函数,浏览器调用)。

生成器函数

声明格式

        function * 函数名(){
    
          
        }

eg:

        function * gen(){
    
    
           console.log('hello generator')
        }
        console.log(gen())

输出:
在这里插入图片描述
没有输出hello generator,并且具有next方法,这是一个迭代器函数

调用格式

所以正确的调用方式:(调用next方法)

        function * gen(){
    
    
           console.log('hello generator')
        }
        let iterator = gen()
        iterator.next()

输出:
在这里插入图片描述

yield

yield是函数代码的分隔符,生成器函数中可以使用yield来分隔函数。
这时调用一个iterator.next()就执行一段被yield分割的代码。

eg:

log.csdnimg.cn/c6f3f2f96ab24ca9aef62c3e19179d94.png)

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <script>
        function * gen(){
      
      
           console.log('一只没有耳朵')
           yield '1';
           console.log('一只没有尾巴')
           yield '2';
           console.log('真奇怪')
           yield '3';
           console.log('真奇怪')
        }
        let iterator = gen()
        iterator.next()
        iterator.next()
        iterator.next()
        iterator.next()
        
    </script>
</body>
</html>

执行如下语句:

        let iterator = gen()
        console.log(iterator.next())
        console.log(iterator.next())
        console.log(iterator.next())
        console.log(iterator.next())

输出:
在这里插入图片描述
发现这是一个迭代器可以直接使用for of:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <script>
        function * gen(){
      
      
           console.log('一只没有耳朵')
           yield '1';
           console.log('一只没有尾巴')
           yield '2';
           console.log('真奇怪')
           yield '3';
           console.log('真奇怪')
        }
        for(let v of gen()){
      
         
        }
        console.log('--------------------------')

        for(let v of gen()){
      
       
            console.log(v)
        }
        
    </script>
</body>
</html>

在这里插入图片描述

生成器的函数参数

可以直接给生成器函数传参,
next()方法可以传入实参,该实参将作为上一个yield的返回结果.
EG:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        function * gen(arg){
      
      
            console.log(arg)
            let first = yield 111
            console.log(first)
            let second = yield 222
            console.log(second)
            let third = yield 333
            console.log(third)
        }

        let iterator = gen('AAA')
        console.log(iterator.next())
        // next()方法可以传入实参,该实参将作为上一个yield的返回结果
        console.log(iterator.next('BBB'))
        console.log(iterator.next('CCC'))
        console.log(iterator.next('DDD'))
    </script>
</body>
</html>

输出:
在这里插入图片描述

生成器的异步编程

js是一个单线程的,所以很多js操作都是异步的,如:
文件操作、网络操作(ajax, request)、数据库操作

定时器异步操作

需求:1s后控制台输出111 ,2s后输出 222,3s后输出333

  • 定时器实现:
    <script>
        setTimeout(()=>{
    
    
            console.log(111);
            setTimeout(()=>{
    
    
                console.log(222);
                setTimeout(()=>{
    
    
                    console.log(333);    
                },3000)    
            },2000)    
        },1000)
    </script>

(箭头函数时回调函数的一种)
通过回调里面套回调,不停的回调来实现异步操作,这就出现了回调地狱。

  • 生成器函数实现异步
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // setTimeout(()=>{
      
      
        //     console.log(111);
        //     setTimeout(()=>{
      
      
        //         console.log(222);
        //         setTimeout(()=>{
      
      
        //             console.log(333);    
        //         },3000)    
        //     },2000)    
        // },1000)

        function one(){
      
      
           setTimeout(()=>{
      
      
                console.log(111)
                iterator.next()
           },1000)
        }
        function two(){
      
      
           setTimeout(()=>{
      
      
                console.log(222)
                iterator.next()
           },2000)
        }
        function three(){
      
      
           setTimeout(()=>{
      
      
                console.log(333)
                iterator.next()
           },3000)
        }

        function * gen(){
      
      
           yield one()
           yield two()
           yield three()
        }

        // 调用生成器函数
        let iterator=gen()
        iterator.next()

    </script>
    
</body>
</html>

异步获取数据

需求:依次获取用户数据、订单数据、商品数据

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>

        function getUsers(){
      
      
           setTimeout(()=>{
      
      
               let data = '用户数据'
               // 调用next,并将数据传入,那么该数据将作为第一个yield的返回结果
               iterator.next(data)
           },1000)
        }
        function getOrders(){
      
      
           setTimeout(()=>{
      
      
               let data = '订单数据'
               iterator.next(data)
           },1000)
        }
        function getGoods(){
      
      
           setTimeout(()=>{
      
      
               let data = '商品数据'
               iterator.next(data)
           },1000)
        }

        function * gen(){
      
      
           let users = yield getUsers();
           console.log(users)
           let orders = yield getOrders()
           console.log(orders)  
           let goods = yield getGoods()
           console.log(goods)
        }

        // 调用生成器函数
        let iterator=gen()
        iterator.next()

    </script>
    
</body>
</html>

输出;
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/mantou_riji/article/details/124782072