初识设计模式,设计模式在js(ts)中的应用(四)

36 阅读2分钟

一、迭代器模式

定义

按一定顺序访问一个集合,使用者无需知道集合的内部结构(封装)。

例子

       class Iterator {
            constructor(container) {
                this.list = container.list
                this.index = 0
            }
            next() {
                if(this.hasNext()) {
                    return this.list[this.index++]
                }
                return null
            }
            // 是否还能往下走
            hasNext() {
                if(this.index == this.list.length) {
                    return false
                }
                return true
            }
       }
       class Container {
            constructor(list) {
                this.list = list
            }
            // 生成迭代器
            getIterator() {
                return new Iterator(this)
            }
       }
       let arr = [1,2,3,4,5];
       let container = new Container(arr);
       let iterator = container.getIterator();
       while(iterator.hasNext()) {
            console.log(iterator.next()); // 1 2 3 4 5
       }

例子

一、ES6中的Iterator

ES6中,有序集合的数据类型有很多(Array Map Set String arguments...),每个都写一个遍历方法就会很繁杂,所以用一个统一的接口来遍历所有的数据类型。

上述数据类型都有Symbol.iterator属性。这个属性是一个函数,执行后返回一个迭代器。for...of...语法就是调用了这个迭代器。

        function each(data, cb) {
            // 生成遍历期
            let iterator = data[Symbol.iterator]()
            let item = iterator.next()
            while(!item.done) { // done属性用来判断是否到最后一位
                cb(item.value); // value是当前遍历到的值
                item = iterator.next(); // 指向迭代器的下一位
            }
        }
        let arr = [1,2,3,4,5,6];
        let nodeList = document.getElementsByTagName('p');
        each(arr,item => {
            console.log(item); // 1 2 3 4 5 6
        })
        each(nodeList,item => {
            console.log(item);
        })
        for(item of arr) {
            console.log(item) // 1 2 3 4 5 6
        }
        for(item of nodeList) {
            console.log(item)
        }

从上面的例子可以看出来,其实for...of...语法就是我们自定义的each函数的语法糖。

对于对象之类的没有迭代器的数据类型,我们可以自定义迭代器,让数据按我们想要的顺序进行遍历。

        let fakeArray = {
            _values: [1,2,3,4,5,6],
            [Symbol.iterator]() {
                let _values = this._values;
                let _index = 0;
                let done = function() {
                    return _index >= _values.length;
                }
                return {
                    next() {
                        return done() ? {
                            value: _values[_index],
                            done: true,
                        } : {
                            value: _values[_index++],
                            done: false,
                        }
                    }
                }
            }
        }  
        for(item of fakeArray) {
            console.log(item) // 1 2 3 4 5 6
        }

ES6的iterator就很好的使用了迭代器模式的思想,用for...of...的时候,数据按照一定顺序遍历,但我们不关心他的遍历顺序。

二、Generator

ES6中,iterator也运用到了generator(生成器函数)当中。通过Generator和Promise可以完美解决异步问题。在这里不做过多讲述,感兴趣的小伙伴可以自行查阅资料。

设计原则

迭代器对象和目标对象分离

迭代器将使用者与目标对象隔离开

符合开放封闭原则