遍历器iterator
ES6之后数据结构除了数组和对象,又添加了Map和Set。遍历器是一种接口规格,任何数据结构只要部署这个接口,就可以完成遍历操作
提供了一个指针,通过指针的指向进行遍历操作
它提供了一个指针,默认指向当前数据结构的起始位置。也就是说,遍历器返回一个内部指针,
第一次调用next方法,将指针指向第一个成员,第二次调用next方法,指针指向第二个成员
下面是一个模拟遍历器指针的例子
function makeIterator(array) {
let nextIndex = 0
return {
next: function() {
return (nextIndex < array.length) ? {value: array[nextIndex++], done: false} : {value: undefined, done: true}
}
}
}
let it = makeIterator(['a', 'b'])
it.next() // {value: 'a', done: false}
it.next() // {value: 'b', done: false}
it.next() // {value: 'undefined', done: false}
遍历器是一个对象,具有next方法,调用next方法,就可以遍历事先给定的数据结构
Iterator接口的目的,就是为所有的数据结构提供一种统一的访问机制,就是for of循环
默认的Iterator接口部署在数据结构的Symbol.iterator
属性,或者说数据结构具有该属性就可以认为是可遍历的
有三类数据结构原生具备了Iterator接口:数组、类数组对象、Set和Map,可以直接使用for of方法
而对象需要在Symbol.iterator
的属性上部署遍历器方法,才可以for of
下面是通过遍历器实现指针结构的例子
// 在原型链上部署System.iterator方法,调用该方法,会返回遍历器对象iteator。调用该对象的next方法,在返回一个值的同时,自动将内部指针指向下一个实例
function test (value) {
this.value = value
this.next = null
}
test.prototype[Symbol.iterator] = function () {
let iterator = {
next: next // iterator.next是一个function
}
let current = this
function next () {
if (current) {
let value = current.value
let done = current == null
current = current.next
return {
value: value,
done: done
}
} else {
return {
done: true
}
}
}
return iterator
}
let one = new test(1),
two = new test(2),
three = new test(3);
one.next = two
two.next = three
for (let i of one) {
console.log(i) // 1 2 3
}
还有一种简单操作,对于类数组对象
NodeList.prototypoe[Symbol.iterator] = Array.prototype[Symbol.iterator]
默认调用iterator接口的场合
- 解构赋值
- 扩展运算符
- yield*
- Arrat.from()
- Map和Set
部署Symbol.iterator最简单实现是结合Generator
let myIterable = []
myiIterable[Symbol.iterator] = function* () {
yield 1
yield 2
yield 3
}
[...myIterable] // [1, 2, 3]
// 或者
let obj = {
* [Symbol.iterator]() {
yield 'hello'
yield 'world'
}
}
for (let x of obj) {
console.log(x) // hello world
}
- 而对于对象来说,是不能直接使用for of的,需要使用yield包装以下
// 以下情况报错
let e = {
a: 1,
b: 'bbb'
}
for (let [key, value] of e) {
console.log() // error,e is not iterable
}
// 使用yield包装一下
function* (obj) {
for (let key of Object.keys(obj)) {
yield [key, obj[key]]
}
}
for (let [key, value] of entries(obj)) {
console.log(key, '->', value)
}
// a -> 1
// b -> 2
// c -> 3
JavaScript 原有的 for…in 循环,只能获得对象的键名,不能直接获取键值。ES6 提供 for…of 循环,允许遍历获得键值。
var arr = ["a", "b", "c", "d"];
for (a in arr) {
console.log(a); // 0 1 2 3
}
for (a of arr) {
console.log(a); // a b c d
}