【ES6系列】Iterator 遍历器

ES6如何让不支持遍历的数据结构“可遍历”?

1、简单数据结构的同类数据聚合

// 简单数据结构的同类数据聚合
// 业务场景:聚合不同图书类型的作者
let authors = {
  allAuthors: {
    fiction: ['Agla', 'Skks', 'LP'],
    scienceFiction: ['Neal', 'Mike', 'Ribert'],
    fantasy: ['J.R.Tole', 'J.M.R', 'Terry P.K']
  },
  Addres: []
}

let r = []
for (let [k, v] of Object.entries(authors.allAuthors)) { // 转换成可遍历对象
  r = r.concat(v)
}
console.log(r) //  ["Agla", "Skks", "LP", "Neal", "Mike", "Ribert", "J.R.Tole", "J.M.R", "Terry P.K"]

Iterator自定义遍历器语法解读:在对象上挂载一个 Symbol.iterator,赋值给一个方法,这个方法的输入是this也就是对象本身,输出是一个对象,对象上必须有一个next方法,且next方法必须返回一个对象,对象有两个字段done和value

let authors = {
  allAuthors: {
    fiction: ['Agla', 'Skks', 'LP'],
    scienceFiction: ['Neal', 'Mike', 'Ribert'],
    fantasy: ['J.R.Tole', 'J.M.R', 'Terry P.K']
  },
  Addres: []
}

authors[Symbol.iterator] = function () {
  return { // 在自定义接口中返回一个对象,这个对象有一个next()方法
    next() { 
      return { // next()方法返回一个对象,对象必须包含两个字段 done value
        done: false, // false 遍历没有结束  true 遍历已结束
        value: 1 // 当前被遍历项的值
      }
    }
  }
}

1. 迭代器协议

属性必选
next返回一个对象的无参函数,被返回对象拥有两个属性:done 和 valueY

这是两个概念:可迭代协议、迭代器协议。通俗的讲,迭代器协议要求符合以下条件:

  1. 首先,它是一个对象
  2. 其次,这个对象包含一个无参函数 next
  3. 最后,next 返回一个对象,对象包含 done 和 value 属性。其中 done 表示遍历是否结束,value 返回当前遍历的值。

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

2. 可迭代协议

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

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

属性必选
[Symbol.iterator]返回一个对象的无参函数,被返回对象符合迭代器协议Y

如果让一个对象是可遍历的,就要遵守可迭代协议,该协议要求对象要部署一个以 Symbol.iterator 为 key 的键值对,而 value 就是一个无参函数,这个函数返回的对象要遵守迭代器协议。

authors[Symbol.iterator] = function () {
  let allAuthors = this.allAuthors // 输入用this来访问,指对象本身
  let keys = Reflect.ownKeys(allAuthors)
  let values = []

  return { // 在自定义接口中返回一个对象,这个对象有一个next()方法
    next() {
      if (!values.length) {
        if (keys.length) {
          values = allAuthors[keys[0]]
          keys.shift()
        }
      }
      return { // next()方法返回一个对象,对象必须包含两个字段 done value
        done: !values.length, // false 遍历没有结束  true 遍历已结束
        value: values.shift() // 当前被遍历项的值
      }
    }
  }
}

let r = []
for (let v of authors) {
  r.push(v)
}
console.log(r) // ["Agla", "Skks", "LP", "Neal", "Mike", "Ribert", "J.R.Tole", "J.M.R", "Terry P.K"]

结合Generator实现

authors[Symbol.iterator] = function* () {
  let allAuthors = this.allAuthors
  let keys = Reflect.ownKeys(allAuthors)
  let values = []
  while (1) {
    if (!values.length) {
      if (keys.length) {
        values = allAuthors[keys[0]]
        keys.shift()
        yield values.shift()
      } else {
        return false
      }
    } else {
      yield values.shift()
    }
  }
}

let r = []
for (let v of authors) {
  r.push(v)
}
console.log(r) // ["Agla", "Skks", "LP", "Neal", "Mike", "Ribert", "J.R.Tole", "J.M.R", "Terry P.K"]

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值