js遍历对象篇(三)-Iterator

861 阅读2分钟

系列链接:

js遍历对象篇(一)-for...in和Object.keys

js遍历对象篇(二)-可枚举性和Symbol

Iterator(遍历器)

ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性(指向该对象的默认遍历器方法),或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)。Symbol.iterator属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器。至于属性名Symbol.iterator,它是一个表达式,返回Symbol对象的iterator属性,这是一个预定义好的、类型为 Symbol 的特殊值,所以要放在方括号内。

原生具备 Iterator 接口的数据结构如下:

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象 以上Iterator相关介绍文字引自阮一峰老师ES6教程
let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();
console.log(iter.next()); // { value: 'a', done: false }
console.log(iter.next()); // { value: 'b', done: false }
console.log(iter.next()); // { value: 'c', done: false }
console.log(iter.next()); // { value: undefined, done: true }

添加iterator接口

1. 给对象添加iterator接口

for...of...遍历对象需要iterator接口

// 由于Object对象没有原生Iterator接口,无法遍历对象
// const obj = {
//   name: 'lsc',
//   age: 21
// }

// for (let item of obj) {
//   console.log(item);  // TypeError: obj is not iterable
// }

// 给对象添加iterator接口
const obj2 = {
  name: 'lsc',
  age: 21,
  height: 187,
  [Symbol.iterator] () {
    const self = this
    const keys = Object.keys(self)
    let index = 0
    return {
      next() {
        if (index < keys.length) {
          return {
            value: self[keys[index++]],
            done: false
          }
        } else {
          return {value: undefined, done: true}
        }
      }
    }
  }
}

for (let item of obj2) {
  console.log(item);
}
2. 给类数组添加iterator接口

arguments/nodelist等常见伪数组本身就有iterator接口,所以这里记录原生伪数组

// 手写伪数组 此例子源于阮一峰ES6教程
let iterable = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
  console.log(item); // 'a', 'b', 'c'
}

但更简便的方法是用扩展运算符或Array.from将伪数组直接转化为数组

Generator

Generator既是状态机,又是遍历器生成函数,因此可以把Generator赋值给对象的Symbol.iterator属性

const obj2 = {
  name: 'lsc',
  age: 21,
  height: 187,
  [Symbol.iterator]: function* myIterator(){
    for(let key of Object.keys(this))
      yield this[key];
  }
}

for (let item of obj2) {
  console.log(item); // lsc 21 187
}