ES6-24【生成器与迭代器的应用】

一、生成器与迭代器的应用

  1. 遍历

    遍历的核心就是从一个容器里面东西都拿出来

    每一次遍历的过程中,要对遍历的结果进行处理,而不是每一次都要处理的情况,那么用遍历本身是不合适的

  2. 迭代与遍历区别

    1. 遍历

      把容器里的所有东西都观察一遍、拿一遍

    2. 迭代

      在本次遍历的过程中进行一次程序上的输出

      在遍历的过程当中,循环到当前这一次的时候,就是整个循环功能的一次迭代

      项目迭代:根据本次的结果进行一次更新,进行一次修复,进行一次小的功能叠加

      在遍历过程当中进行某一次程序的输出的话,那么就必须要有一个叫迭代器的东西

  3. 迭代器(iterator)

    迭代器可以在遍历的时候一次一次的执行,而不是整个都执行,它会根据你的指令去遍历指定次数

    但它有一个问题:就是迭代器还不能直接使用,因为迭代器是建立在遍历的基础上的,不可能遍历某一次,需要借助生成器

  4. 生成器(generator)

    1. 概念

      就是生产迭代器的东西

      由于代器是建立在遍历的基础上的,而生成器就是利用遍历造出一个迭代器

    2. 生成器及yield

      这就是一个生成器,实例化出来的就是一个迭代器

      function * test() {}
      

      但它还是需要依赖遍历,它生产迭代器的关键点就在于yield,因为yield可以让这个遍历停下来

      var arr = [1, 2, 3, 4, 5, 6];
      function * test(arr) {
          for (var item of arr) {
              yield item;
          }
      }
      let iterator = test(arr); // 实例化(生产)出来一个迭代器,传入迭代对象
      
    3. next

      对迭代器进行迭代,返回值是{ value: xxx, done: boolean }(value是抽取的值(对应yield产出的值),done则是否迭代完毕)

      var arr = [1, 2, 3, 4, 5, 6];
      function* test(arr) {
          for (var item of arr) {
              yield item;
          }
      }
      let iterator = test(arr);
      console.log(iterator.next()); // { value: 1, done: false }
      console.log(iterator.next()); // { value: 2, done: false }
      console.log(iterator.next()); // { value: 3, done: false }
      console.log(iterator.next()); // { value: 4, done: false }
      console.log(iterator.next()); // { value: 5, done: false }
      console.log(iterator.next()); // { value: 6, done: false }
      console.log(iterator.next()); // { value: undefined, done: true }
      
  5. ES5实现生成器

    var arr = [1, 2, 3, 4, 5, 6];
    function generator(arr) {
        var i = 0;
        return {
            next() {
                var done = i > arr.length ? true : false,
                    value = done ? 'undefined' : arr[i++];
                return {
                    value: value,
                    done: done
                }
            }
        }
    }
    let iterator = generator(arr);
    console.log(iterator.next()); // { value: 1, done: false }
    console.log(iterator.next()); // { value: 2, done: false }
    console.log(iterator.next()); // { value: 3, done: false }
    console.log(iterator.next()); // { value: 4, done: false }
    console.log(iterator.next()); // { value: 5, done: false }
    console.log(iterator.next()); // { value: 6, done: false }
    console.log(iterator.next()); // { value: undefined, done: true }
    
  6. 需求

    1. 从test1依次执行到test5

      var functions = [
          function test1() {
              console.log('test1');
          },
          function test2() {
              console.log('test2');
          },
          function test3() {
              console.log('test3');
          },
          function test4() {
              console.log('test4');
          },
          function test5() {
              console.log('test5');
          }
      ];
      for (let item of functions) {
          item();
      }
      // test1
      // test2
      // test3
      // test4
      // test5
      
    2. 执行到某一个地方截断(执行到test3停止 )

      var functions = [
          function test1() {
              console.log('test1');
              return true;
          },
          function test2() {
              console.log('test2');
              return true;
          },
          function test3() {
              console.log('test3');
              return false;
          },
          function test4() {
              console.log('test4');
              return true;
          },
          function test5() {
              console.log('test5');
              return true;
          }
      ];
      for (let item of functions) {
          if (!item()) {
              break;
          };
      }
      // test1
      // test2
      // test3
      

      这种截断是不可取的,因为它是建立在遍历的基础上的,而我们必须建立在迭代的基础上

  7. 中间件(node express)

    中间件集合:[test1,test2,test3,test4](token是否存在 => token是否合法 => token是否过期 => 打开页面)

    当用户访问一个路由 /user 的时候,这些中间件集合就会执行

    但只要其中一个中间件有问题,就会截断后续中间件的执行

    在学习express、koa的时候,你会发现每一个中间件函数里面都会存在一个next的东西,也就是说在next执行的时候才会去执行下一个中间件函数

    var functions = [
        function test1(next) {
            console.log('test1');
            next(); // 如果中间有哪一个next没有执行,那么后续的中间件是不会执行的,这就是迭代过程中的截断
        },
        function test2(next) {
            console.log('test2');
            next();
        },
        function test3(next) {
            console.log('test3');
            next();
        },
        function test4(next) {
            console.log('test4');
            next();
        },
        function test5(next) {
            console.log('test5');
            next();
        }
    ];
    
  8. 生成器实现中间件

    1. 源码实现

      ;(function(functions) {
          function* generator(arr) {
              for (var i = 0; i < arr.length; i++) {
                  yield arr[i];
              }
          }
          var iterator = generator(functions);
          var init = () => {
              nextDo(iterator.next());
          }
          function nextDo(n) {
              n.value(function() { // 这个函数其实就是next,为什么要传这个函数呢,因为它是连续执行的关键,如果next有执行就继续往下执行,如果没有就截断,而继续往下执行就是通过nextDo递归的方式实现的,递归时会判断是否迭代完成,如果否则继续迭代,如果是就终止递归
                  var n = iterator.next(); // 拿到当前的迭代器对象
                  if (!n.done) { // 判断时候迭代完成,如果没有就继续迭代,如果是就终止递归
                      nextDo(n);
                  } else {
                      return
                  }
              });
          }
          init();
      })(
          [
              function test1(next) {
                  console.log('test1');
                  next();
              },
              function test2(next) {
                  console.log('test2');
                  next();
              },
              function test3(next) {
                  console.log('test3');
                  // 判断是否有token,有就往下执行,没有就什么都不做
                  //if(token){
      			//	next();
      			//}
      			next();
              },
              function test4(next) {
                  console.log('test4');
                  next();
              },
              function test5(next) {
                  console.log('test5');
                  next();
              }
          ]
      );
      // test1
      // test2
      // test3
      // test4
      // test5
      
    2. 插件使用

      middleware.js下载

      // 导入中间件插件
      import M from "./middleware.js";
      M([checkInputValue, submitData, loginSuccess])
      // 表单验证
      function checkInputValue(){
          if(......) {
              next();
          }
      }
      // 登录提交
      function submitData() {
          $.ajax({
              ......
              success: function(data){
                  if(xxxx) {
                      next();
                  }
              }
          })
      }
      // 登录成功
      function loginSuccess() {
          location.href = '......'
      }
      
  9. 迭代器使用场景 —— 操作日志

    index.html

    <input type="text" id="content">
    <button id="btn">操作</button>
    <ul class="log-list"></ul>
    <script src="./index.js"></script>
    

    index.js

    ;(() => {
        var oContent = document.getElementById('content'),
            oBtn = document.getElementById('btn'),
            oList = document.getElementsByClassName('log-list')[0];
    
        let log = [],
            it = generator(log);
    
        const init = () => {
            bindEvent();
        }
    
        function bindEvent() {
            oBtn.addEventListener('click', handleBtnClick, false);
        }
    
        function handleBtnClick() {
            const value = oContent.value;
    
            log.push({
                value,
                dateTime: new Date()
            })
    
            _addLog(it.next().value);
        }
    
        function _addLog(log) {
            const oLi = document.createElement('li');
            oLi.innerHTML = `
            <p>增加一项:${log.value}</p>
            <p>操作事件:${log.dateTime}</p>
            `
    
            oList.appendChild(oLi);
        }
    
        function* generator(arr) {
            for (let item of arr) {
                yield item;
            }
        }
    
        init();
    })();
    

    迭代器的迭代是有记忆的,它会基于上一次进行下一次迭代,就不用考虑用下标,这也是它好用的地方

    生成器、迭代器用得更多的还是底层封装,比如TJ的co库就用了很多(异步转同步的库),以后学了node可以多看看

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值