面试官:你可以用 for of 遍历 Object 吗?
什么是迭代器模式
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。 ——《设计模式:可复用面向对象软件的基础》
可以说迭代器模式就是为了遍历存在的。提到遍历,大家都对那些手段耳熟能详了,下面我们先简单列一下各种数据类型的遍历:
遍历数组
- for 循环
- forEach
- map
- reduce
- keys
- values
- for of
- ......
其中keys values for of 需要Iterator支持,后面会介绍Iterator
遍历 Map/Set
- keys
- entries
- forEach
- ......
遍历 Object
- for in
- 先Object.keys(obj)得到对象每个属性的数组, 然后使用数组的遍历方法遍历每个 key,就能获取 每个 key 对应的 value
Iterator 和 for of
Iterator是ES6提出的一个接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
Iterator 的作用
- 为各种数据结构,提供一个统一的、简便的访问接口。
- ES6提出了新的遍历命令for...of循环,Iterator 接口主要供for...of消费。
Iterator 的遍历过程
既然数组是支持for...of循环的,那数组肯定部署了 Iterator 接口,我们通过它来看看Iterator 的遍历过程。
从图中我们能看出:
- Iterator 接口返回了一个有next方法的对象。
- 每调用一次 next,依次返回了数组中的项,直到它指向数据结构的结束位置。
- 返回的结果是一个对象,对象中包含了当前值value 和 当前是否结束done
用 for of 遍历 Object
回到标题中的问题,我们现在如何去让一个对象也可以用 for of 来遍历它呢?
根据上面讲到的内容,需要给对象也部署 Iterator 接口(其实就是在Object.prototype上实现一个以Symbol.iterator为名的function,这个function返回一个有next方法的对象,每调用一次 next, 能够依次返回数组中的项,直到它指向数据结构的结束位置 )
function objectIterator() { const keys = Object.keys(this) let index = 0 return { next: () => { const done = index >= keys.length const value = done ? undefined : this[keys[index]] index++ return { done, value } } } } Object.prototype[Symbol.iterator] = objectIterator const obj = { key: '1', value: '2' } for (const iterator of obj) { console.log(iterator) }