es6学习:迭代器和生成器

1. 迭代器

      迭代器(iterator)是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署iterator接口,就可以完成遍历操作。当需要自定义遍历数据的时候,要想到迭代器。

  • es6 创造了一种新的遍历命令for...of循环,iterator接口主要供for...of消费
  • 原生具备iterator接口的数据(可用for...if遍历)

           Array   Arguments   Set   Map   String   TypedArray   NodeList

  • 工作原理

           1)(由Symbol.interator创建)创建一个指针对象,指向当前数据结构的起始位置;

           2)第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员;

           3)接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员;

           4)每调用next方法返回一个valuedone属性的对象

    // 声明一个数组
    const test = ['a', 'b', 'c', 'd']
    
    // 使用for of 遍历数组  输出的是键值对的值
    for (let v of test) {
      console.log(v)
    }

    // 使用for in 遍历数组  输出的是键值对的序号
    for (let v in test) {
      console.log(v)
    }

      数组能够使用for of的原因,是因为__proto__中有iteator的属性。

      将iterator取出来手动调用next方法,当调用完数据结构的最后一个成员后,其value值为undefined , 具体的结果为:

    let iterator = test[Symbol.iterator]()
    // 调用对象的next方法
    console.log(iterator.next())
    console.log(iterator.next())
    console.log(iterator.next())
    console.log(iterator.next())
    console.log(iterator.next())

      手动书写迭代器,根据自己的需求进行迭代数据。例子如下:

    // 例子 --  当遍历family对象时 输出的是family.persons的值
    const family = {
      name: '张氏一家',
      persons: [
        'father Zhang',
        'mother Zhang',
        'son',
        'daughter',
        'dog'
      ],
      [Symbol.iterator] () {
        let index = 0; // 索引变量
        let _this = this
        return {
          next: function () {
            if (index < _this.persons.length) {
              index ++ // 指向下一个
              return { value: _this.persons[index], done: false}
            } else {
              return { value: undefined, done: true}
            }
          }
        }
      }
    }
    
    for (let value of family) {
      console.log(value)
    }

      将代码进行修改:简写function为箭头函数,此时的this就可以直接使用

    const family = {
      name: '张氏一家',
      persons: [
        'father Zhang',
        'mother Zhang',
        'son',
        'daughter',
        'dog'
      ],
      [Symbol.iterator] () {
        let index = 0; // 索引变量
        return {
          next: () => {
            if (index < this.persons.length) {
              index ++ // 指向下一个
              return { value: this.persons[index], done: false}
            } else {
              return { value: undefined, done: true}
            }
          }
        }
      }
    }

       推荐一篇文档,关于iterator迭代器: https://segmentfault.com/a/1190000016824284

2. 生成器

      生成器函数是 es6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。

  • 声明与传统函数不同
    function * AAA () {
      
    }
或
    function* AAA () {
      
    } 
或
    function *AAA () {
      
    }
  • 执行特殊 ( 借助于 next() 方法执行 ) 
    function * AAA () {
      console.log('hello generator !')
    }
    let iterator = AAA()
    console.log(iterator)
    // 借助于next()方法执行
    iterator.next()

2.1 yield

      yield的理解:函数代码的分隔符,三个yield将函数分为了四块。yield 关键字使生成器函数暂停执行,并返回跟在它后面的表达式的当前值。与return类似,但是可以使用next方法让生成器函数继续执行函数yield后面内容,直到遇到yield暂停或return返回或函数执行结束。

      yield 后的内容为迭代器中value的值。当next()执行后,会暂行执行,当再次运行next(),会在之前的进度上执行下去。

    // yeild 函数代码的分隔符
    function * AAA () {
      yield 'AAA is a dog'
      yield 'aaa is a cat'
      yield 'BBB is a tiger'
    }
    let iterator = AAA()
    // 借助于next()方法执行
    console.log(iterator.next())
    // 遍历
    for (let v of AAA()) {
      console.log(v)
    }

2.2 参数

      可以整体传参,在获取迭代器对象的时候传参;也可以通过next()方法进行传参。通过next方法传的参数可以作为上一个yiled的返回值。整体传参,与匿名函数传参相同。代码和效果如下

    function * test (arg) {
      console.log(arg)
      let one = yield 11111
      console.log(one)
      let two = yield 22222
      console.log(two)
      let three = yield 33333
      console.log(three)
    }
    // 执行获取迭代器对象
    let iterator = test ('param')
    console.log(iterator.next())
    // next 方法可以传参,传的参数作为上一个yiled的返回值
    console.log(iterator.next('我要作为yiled 11111 的返回值'))
    console.log(iterator.next('我要作为yiled 22222 的返回值'))
    console.log(iterator.next('我要作为yiled 33333 的返回值'))

2.3 异步编程

      文件操作、网络操作(ajax, request)、数据库操作等涉及到异步编程。以下代码是一个例子,通过yield控制任务的相继延迟输出,能够解决回调地狱的问题(setTimeout嵌套的现象)。

    // 需求:1s后控制台输出111  然后2s后输出222  然后3s后输出333
    // 现象:解决回调地狱
    // 任务一
    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 * test () {
      yield one()
      yield two()
      yield three()
    }
    let iterator = test()
    iterator.next()

      通过异步获取数据(数据之间关联,比如订单数据在获取用户数据之后获取),其中较难的是数据之间的传递和接收处理,通过next传参的特点进行。例子二如下

    // 需求:异步处理 用户数据 订单数据 商品数据,并进行数据之间的传递
    // 任务一
    function getUsers () {
      setTimeout(() => {
        let data = '用户数据'
        iterator.next(data) // 进行数据传递, 方便操作数据
      }, 1000)
    }
    // 任务二
    function getOrders () {
      setTimeout(() => {
        let data = '订单数据'
        iterator.next(data) // 进行数据传递, 方便操作数据
      }, 1000)
    }
    // 任务三
    function getGoods () {
      setTimeout(() => {
        let data = '商品数据'
        iterator.next(data) // 进行数据传递, 方便操作数据
      }, 1000)
    }
    
    function * test () {
      let users = yield getUsers() // 接收传递的数据
      console.log(users)
      let orders = yield getOrders() // 接收传递的数据
      console.log(orders)
      let goods = yield getGoods() // 接收传递的数据
      console.log(goods)
    }
    let iterator = test()
    iterator.next()

 


进入下一篇 ... ...

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值