美文网首页
ES6(十五)—— lterator

ES6(十五)—— lterator

作者: 顽皮的雪狐七七 | 来源:发表于2020-09-27 13:44 被阅读0次

    目录

    • ES6如何让不支持遍历的结构可遍历?
      • 将所有的作者名称取出来
      • for-of需要Object.entries进行转化
    • 规定
      • 可迭代协议 —— 去找对象上面有没有Symbol.iterator属性
      • 迭代器协议 —— 怎么个迭代方式?返回无参函数next,next返回一个对象包含done和value属性
    • Generator 和 lterator 结合使用
    • 案例
    • ES6-ES10学习版图

    ES6如何让不支持遍历的结构可遍历?

    let authors = {
      allAuthors: {
        fiction: [
          'Agatha Christie',
          'J. K. Rowling',
          'Dr. Seuss'
        ],
        scienceFiction: [
          'Neal Stephenson',
          'Arthur Clarke',
          'Isaac Asimov',
          'Robert Heinlein'
        ],
        fantasy: [
          'J. R. R. Tolkien',
          'J. K. Rowling',
          'Terry Pratchett'
        ]
      }
    }
    

    将所有的作者名称取出来

    ES5的做法

    allAuthors进行遍历,看看取值情况

    for(let [k,v] of Object.entries(authors.allAuthors)){
      console.log(k,v)
    }
    //fiction (3) ["Agatha Christie", "J. K. Rowling", "Dr. Seuss"]
    //scienceFiction (4) ["Neal Stephenson", "Arthur Clarke", "Isaac Asimov", "Robert Heinlein"]
    // fantasy (3) ["J. R. R. Tolkien", "J. K. Rowling", "Terry Pratchett"]
    
    // 所以正确的写法是:
    let r = []
    for(let [k,v] of Object.entries(authors.allAuthors)){
      r = r.concat(v)
    }
    console.log(r)
    //["Agatha Christie", "J. K. Rowling", "Dr. Seuss", "Neal Stephenson", "Arthur Clarke", "Isaac Asimov", "Robert Heinlein", "J. R. R. Tolkien", "J. K. Rowling", "Terry Pratchett"]
    

    每次都需要遍历,而且还要对obj不支持遍历的对象进行改造。
    而且还需要知道authors的内部结构。

    我们的目标是:

    • 写法优雅
    • 数据结构种的内置逻辑不需要关心
    let r = []
    for(let v of authors){
        console.log(v)
        r.push(v)
    }
    

    所以ES6的写法

    //固定写法
    authors[Symbol.iterator] = function () {
      // 输入 this,对象本身
      let allAuthors = this.allAuthors
      let keys = Reflect.ownKeys(allAuthors)
      console.log(keys) // ["fiction", "scienceFiction", "fantasy"]
      let values = [] // 是key的值
      return {
        // 必须返回一个方法
        next () {
          console.log(values)
          //一开始values.length是0,如果是0就进入循环过程
          if (!values.length) {
            if (keys.length) { 
              values = allAuthors[keys[0]]
              keys.shift() //永远取第一个元素,用完之后进行弹出
            }
          }
          // 必须返回两个值
          return {
            done: !values.length,
            value: values.shift()
          }
        }
      }
    }
    
    let r = []
    for(let v of authors){
      r.push(v)
    }
    console.log(r)
    //["Agatha Christie", "J. K. Rowling", "Dr. Seuss", "Neal Stephenson", "Arthur Clarke", "Isaac Asimov", "Robert Heinlein", "J. R. R. Tolkien", "J. K. Rowling", "Terry Pratchett"]
    

    for-of需要Object.entries进行转化

    let obj = {
        1: "hello",
        "a":"hi"
    };
    
    for(let i of obj){console.log(i,obj[i]);}
    //报错:Uncaught TypeError: obj is not iterable
    
    let obj1 = Object.entries(obj);
    console.log(obj1) //[Array(2), Array(2)]
    
    for(let [k,v] of obj1){
        console.log(k,v)
    }
    //1 hello
    //a hi
    

    规定

    可迭代协议 —— 去找对象上面有没有Symbol.iterator属性

    • 可迭代协议允许 JavaScript 对象去定义或定制它们的迭代行为, 例如(定义)在一个 for…of 结构中什么值可以被循环(得到)。一些内置类型都是内置的可迭代类型并且有默认的迭代行为, 比如 Array or Map, 另一些类型则不是 (比如Object) 。

    • 为了变成可迭代对象, 一个对象必须实现 @@iterator 方法, 意思是这个对象(或者它原型链 prototype chain 上的某个对象)必须有一个名字是 Symbol.iterator 的属性

    • 这里参考 遍历 —— for-of(ES6新增)

    迭代器协议 —— 怎么个迭代方式?返回无参函数nextnext返回一个对象包含donevalue属性

    PS: 这个结构是不是和Generator特别像?

    如果 next 函数返回一个非对象值(比如falseundefined) 会展示一个 TypeError (“iterator.next() returned a non-object value”) 的错误

    //固定写法
    authors[Symbol.iterator] = function () {
      // 输入 this,对象本身
      // 输出 返回值(格式要求)
      return {
        // 必须返回一个next方法
        next () {
          // 必须返回两个值
          return {
            done: false, // boolean false-遍历没有结束 true-遍历结束
            value: 1 // 当前遍历的项目的值
          }
        }
      }
    }
    

    Generator 和 lterator 结合使用

    想了解Generator,参考文章 ES6(十四)—— Generator

    //可迭代协议 加*就是Generator了
    authors[Symbol.iterator] = function * () {
      // 输入 this,对象本身
      let allAuthors = this.allAuthors
      let keys = Reflect.ownKeys(allAuthors)
      console.log(keys) // ["fiction", "scienceFiction", "fantasy"]
      let values = [] // 是key的值
      // 无线循环,如果退出之后,会自动中止退出的
      while(1){
        if(!values.length){
          if(keys.length){
            values = allAuthors[keys[0]]
            keys.shift()
            yield values.shift()
          }else{
            // 退出循环
            return false
          }
        }else{
          yield values.shift()
        }
      }
    }
    

    案例

    • 场景:你我协同开发一个任务清单应用
    • 迭代器的意义: 外部不用去关心内部的结构,直接进行遍历就可以拿到全部数据。
    // each方法,是todos内部暴露的方法
    // 更好的是把todos直接变成一个可迭代的对象
    const todos = {
      life: ['吃饭', '睡觉', '打豆豆'],
      learn: ['语文', '数学', '外语'],
      work: ['喝茶'],
    
      each: function (callback) {
        const all = [].concat(this.life, this.learn, this.work)
        for( const item of all) {
          callback(item)
        }
      },
      [Symbol.iterator]: function() {
        const all = [...this.life, ...this.learn, ...this.work]
        let index = 0
        return {
          next: function () {
            return {
              value: all[index],
              done: index++ >= all.length
            }
          }
        }
      }
    }
    
    todos.each(function(item){
      console.log(item)
    })
    // 吃饭
    // 睡觉
    // 打豆豆
    // 语文
    // 数学
    // 外语
    // 喝茶
    
    for(const item of todos){
      console.log("for-of: " +item)
    }
    

    使用Generator函数实现Iterator方法,对上面的案例进行改进

    const todos = {
      life: ['吃饭', '睡觉', '打豆豆'],
      learn: ['语文', '数学', '外语'],
      work: ['喝茶'],
    
      each: function (callback) {
        const all = [].concat(this.life, this.learn, this.work)
        for( const item of all) {
          callback(item)
        }
      },
      [Symbol.iterator]: function * () {
        const all = [...this.life, ...this.learn, ...this.work]
        for(const item of all) {
          yield item
        }
      }
    }
    
    for(const item of todos){
      console.log(item)
    }
    // 吃饭
    // 睡觉
    // 打豆豆
    // 语文
    // 数学
    // 外语
    // 喝茶
    

    ES6-ES10学习版图

    image

    相关文章

      网友评论

          本文标题:ES6(十五)—— lterator

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