iterator是es6提供用于访问数据遍历的一种机制。
就是数据类型中被提供了Symbol.iterator 接口
**

概念

JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了MapSet。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是MapMap的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。
遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。
Iterator 的遍历过程是这样的。
(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
(2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的next方法,直到它指向数据结构的结束位置。

es6中默认自带Symbol.iterator接口有
原生Array
set
map
nodeList
以及类数组都可以使用for..of

迭代器接口封装**

1.定义function模拟迭代器

  1. var it = makeIterator(['a', 'b']);
  2. it.next() // { value: "a", done: false }
  3. it.next() // { value: "b", done: false }
  4. it.next() // { value: undefined, done: true }
  5. function makeIterator(array) {
  6. var nextIndex = 0;
  7. return {
  8. next: function() {
  9. return nextIndex < array.length ?
  10. {value: array[nextIndex++], done: false} :
  11. {value: undefined, done: true};
  12. }
  13. };
  14. }

2.使用genterator为对象添加一个迭代器

  1. var obj = {
  2. a:11,
  3. b:22,
  4. c:33,
  5. d:['hello word'],
  6. [Symbol.iterator]:function *(){
  7. for(j of Object.keys(obj)) {
  8. yield obj[j];
  9. }
  10. }
  11. }
  12. //print [...obj]
  13. (4) [11, 22, 33, Array(1)]
  14. 0: 11
  15. 1: 22
  16. 2: 33
  17. 3: ["hello word"]
  18. length: 4
  19. __proto__: Array(0)

3.封装一个原生迭代器

  1. var obj3 = {
  2. a:2,
  3. b:3,
  4. c:5,
  5. d:['test']
  6. }
  7. 为当前对象添加自定义封装一个迭代器
  8. obj3[Symbol.iterator] = function(){
  9. var arr = Object.keys(this);
  10. var lenth = Object.keys(this);
  11. let index = 0;
  12. return {
  13. next:function(){
  14. return index < lenth ? {value:arr[index++],done:false} : {done:true}
  15. }
  16. }
  17. }
  18. print
  19. for(var j of obj3){
  20. console.log(j,obj3[j])
  21. }
  22. VM691:2 a 2
  23. VM691:2 b 3
  24. VM691:2 c 5
  25. VM691:2 d ["test"]

4.覆盖原生数组迭代器

  1. Array.prototype[Symbol.iterator] = function * (){
  2. yield 1;
  3. yield 2
  4. }
  5. var arr = [1,2,3]
  6. //展开结果只有1,2
  7. [...arr]
  8. (2) [1, 2]

6.定义一个类数组添加原生数组迭代器

  1. let iterable2 = {
  2. 0: 'a',
  3. 1: 'b',
  4. 2: 'c',
  5. length: 3,
  6. [Symbol.iterator]:Array.prototype[Symbol.iterator]
  7. };
  8. [...iterable2]
  9. (3) ["a", "b", "c"]

调用迭代器场合

有一些场合会默认调用 Iterator 接口(即Symbol.iterator方法),除了下文会介绍的for...of循环,还有几个别的场合。
(1)解构赋值
对数组和 Set 结构进行解构赋值时,会默认调用Symbol.iterator方法。

let set = new Set().add('a').add('b').add('c');
let [x,y] = set;
// x='a'; y='b'
let [first, ...rest] = set;
// first='a'; rest=['b','c'];

(2)扩展运算符
扩展运算符(…)也会调用默认的 Iterator 接口。

// 例一
var str = 'hello';
[...str] //  ['h','e','l','l','o']
// 例二
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']

上面代码的扩展运算符内部就调用 Iterator 接口。
实际上,这提供了一种简便机制,可以将任何部署了 Iterator 接口的数据结构,转为数组。也就是说,只要某个数据结构部署了 Iterator 接口,就可以对它使用扩展运算符,将其转为数组。

let arr = [...iterable];

(3)yield*
yield*后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。

let generator = function* () {
  yield 1;
  yield* [2,3,4];
  yield 5;
};
var iterator = generator();
iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
iterator.next() // { value: 3, done: false }
iterator.next() // { value: 4, done: false }
iterator.next() // { value: 5, done: false }
iterator.next() // { value: undefined, done: true }

(4)其他场合
由于数组的遍历会调用遍历器接口,所以任何接受数组作为参数的场合,其实都调用了遍历器接口。下面是一些例子。

  • for…of
  • Array.from()
  • Map(), Set(), WeakMap(), WeakSet()(比如new Map([['a',1],['b',2]])
  • Promise.all()
  • Promise.race()

具体参考es6语法http://es6.ruanyifeng.com/#docs/iterator