es6-iterator遍历器

参考:http://es6.ruanyifeng.com/#docs/iterator

JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了 MapSet

遍历器(Iterator)是一种访问机制,只要部署了 Iterator 接口,就可以完成遍历操作。

Iterator 的作用有三个:

  • 为各种数据结构,提供一个统一的、简便的访问接口;
  • 使得数据结构的成员能够按某种次序排列;
  • ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费。

Iterator 的遍历过程是这样的。

(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。

(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。

(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。

(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。

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

  • Array
  • String
  • Map
  • Set
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象

以数组Array为例,内部共有 Symbol.iteratorkeysvaluesentries这几种遍历器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const colors = ['red', 'green', 'blue']

// Symbol遍历器
const iterator1 = colors[Symbol.iterator]() // Array Iterator {}
// 调用next(),返回相应的元素值,直到done为true
console.log(iterator1.next()) // {value: "red", done: false}
console.log(iterator1.next()) // {value: "green", done: false}
console.log(iterator1.next()) // {value: "blue", done: false}
console.log(iterator1.next()) // {value: undefined, done: true}
console.log(iterator1.next()) // {value: undefined, done: true}

console.log('--分割线--')

// values遍历器(同Symbil.iterator)
const iterator2 = colors.values() // Array Iterator {}
// 调用next(),返回相应的元素值,直到done为true
console.log(iterator2.next()) // {value: "red", done: false}
console.log(iterator2.next()) // {value: "green", done: false}
console.log(iterator2.next()) // {value: "blue", done: false}
console.log(iterator2.next()) // {value: undefined, done: true}
console.log(iterator2.next()) // {value: undefined, done: true}

console.log('--分割线--')

// keys遍历器
const iterator3 = colors.keys() // Array Iterator {}
// 调用next(),返回相应的索引,直到done为true
console.log(iterator3.next()) // {value: 0, done: false}
console.log(iterator3.next()) // {value: 1, done: false}
console.log(iterator3.next()) // {value: 2, done: false}
console.log(iterator3.next()) // {value: undefined, done: true}
console.log(iterator3.next()) // {value: undefined, done: true}

console.log('--分割线--')

// entries遍历器
const iterator4 = colors.entries() // Array Iterator {}
// 调用next(),返回相应的索引和元素组成的数组,直到done为true
console.log(iterator4.next()) // {value: [0, "red"], done: false}
console.log(iterator4.next()) // {value: [1, "green"], done: false}
console.log(iterator4.next()) // {value: [2, "blue"], done: false}
console.log(iterator4.next()) // {value: undefined, done: true}
console.log(iterator4.next()) // {value: undefined, done: true}

当然我们可以自己编写遍历器,比如我们编写一个 values2 遍历器,实现 values 遍历器的功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Array.prototype.values2 = function () {
let i = 0;
let items = this;
return {
next() {
const done = i >= items.length;
const value = done ? undefined : items[i++]
return {
value,
done
}
}
}
}

const iterator5 = colors.values2() // Array Iterator {}
// 调用next(),返回相应的元素值,直到done为true
console.log(iterator5.next()) // {value: "red", done: false}
console.log(iterator5.next()) // {value: "green", done: false}
console.log(iterator5.next()) // {value: "blue", done: false}
console.log(iterator5.next()) // {value: undefined, done: true}
console.log(iterator5.next()) // {value: undefined, done: true}

同理,
通过查找new String().__proto__可发现,String拥有Symbol.iterator遍历器
通过查找new Map().__proto__可发现,Map拥有Symbol.iterator、keys、values、entries
通过查找new Set().__proto__可发现,Set拥有Symbol.iterator、keys、values、entries
通过查找document.querySelectorAll(‘li’).__proto__可发现,NodeList拥有Symbol.iterator、keys、values、entries