迭代模式

提供一种方法, 可以顺序获得聚合对象中的各个元素。可以让用户通过特定的接口遍历集合中的每一个元素, 而不必了解底层原理。

for循环, 数组的forEach方法。 都是迭代器, 属于内部迭代器(用户无需关心如何实现,只是调用接口就好了,迭代器会完全接手迭代过程)。

外部迭代器: 每一次迭代用户都是可控的。
例如一个iterator,用户想遍历下一个元素, 就调用一次next()函数, 这个函数返回一个对象,里面是当前正在遍历的值, 以及是否完成了整个迭代过程的标志。

let arr = [1,2,3,4,5,6]
let I = myIterator(arr)
I.next() // { value: 1, done: false} ..... {value: 6, done: true}

类似这样的实现, 就是外部迭代器。所以可以尝试实现一下。

function OuterIntertor (arr){
    let curIndex = 0
    let next = () => {
        return {
            value: arr[curIndex],
            done: arr.length === ++ curIndex
        } 
    }
    return {
        next
    }
}
image.png

当然这是一个简单的示例, 如果继续往下遍历, 由于js的机制虽然不会报错, 但是也是可以没有意义地无限的进行下去。

ES6引入了iterator 将其部署在NodeListargumentsArraySetMapString上,在他们的构造函数上可以找到Symbol.iterator. 使得这些数据结构 iterable 的 。 能使用 for, for of, for in, ..., Array.from的操作。

Symbol

Symboljs中的第七种数据类型。它就是一种新的数据类型, 不属于之前任何一种。
Symbol的值是唯一的,尽管脸两个长得一样的Symbol, 他们仍然不相等。

let s1 = Symbol('abc');
let s2 = Symbol('abc');
let obj = {
  [s1]: 'vey1',
  [s2]: 'vey2'
}
console.log(obj)
// {Symbol(abc): "vey1", Symbol(abc): "vey2"}

两个长得一样的Symbol, 代表了不同的值。

部署 Iterator 接口

let obj = {
   0: 'c',
   1: 'b',
   2: 'a',
  length: 3
}
console.log([ ...obj ])
// Uncaught TypeError: obj is not iterable

因为没有iterator接口, 所以不是可以迭代的。
按照ES6的规范去实现它(value, done, next)

var a = {
    0: 'c',
    1: 'b',
    2: 'a',
    length: 3,
    [Symbol.iterator]: function(){
        let curIndex = 0;
        let next = () => {
            return {
                value: this[curIndex],
                done: this.length ===  curIndex ++
            }
        }
        return {
            next
        }
    }
}
[...a] // ["c", "b", "a"]