ECMAScript2015中实现可迭代接口,其实这就是设计模式中的迭代器模式。

假设需要设计一个任务清单应用,首先要设计一个用于存放所有任务的对象,其他人的任务是把这个对象当中所有的任务项全部去罗列呈现到界面上,为了更有结构的去记录每个数据,可以设计一个对象结构。

在这个对象中定义两个数组分别去存放生活类和学习类的任务

const todos = {
    life: ['吃饭', '睡觉', '打豆豆'],
    learn: ['语文', '数学', '外语'],
}

此时对于其他人而言就必须要了解这个对象当中的数据结构是怎么样的,才能够有可能去遍历到这个对象当中全部的数据内容。

对其他人而言,他们可能需要分别去遍历这两个数组。从而去呈现内部所有的任务。

for (const item of todos.life) {
    console.log(item);
}

for (const item of todos.learn) {
    console.log(item);
}

那如果这个时候数据结构发生了变化,例如添加了一个全新的类目,但这里的遍历是和之前的数据结构严重耦合的,所以也需要跟着一起去变化。

const todos = {
    life: ['吃饭', '睡觉', '打豆豆'],
    learn: ['语文', '数学', '外语'],
    work: ['编码']
}

那如果说这个定义的数据结构如果能对外提供一个统一的遍历接口,对于调用者而言就不用去关心对象内部的结构是怎么样的了。更不用关心数据结构改变过后所产生的影响。

例如这里可以在对象内部定义一个each方法,这个方法接收外部的一个回调函数参数,然后在这个函数内部去遍历所有的数据,并且将每个数据都交给这个回调函数。

const todos = {
    life: ['吃饭', '睡觉', '打豆豆'],
    learn: ['语文', '数学', '外语'],
    work: ['编码'],
    each: function (cb) {
        [...this.life, ...this.learn, ...this.work].forEach(cb);
    }
}

这样一来就相当于对外提供了一个统一遍历的接口,对于其他人就会省心很多,因为根本不用关心内部是什么情况,只管调用这里的each这样一个统一的遍历接口就可以了。

实现可迭代接口也是相同的道理,可以使用迭代器来实现这个接口。

const todos = {
    life: ['吃饭', '睡觉', '打豆豆'],
    learn: ['语文', '数学', '外语'],
    work: ['编码'],
    [Symbol.iterator]: function() {
        const all = [...this.life, ...this.learn, ...this.work];
        let index = 0;
        return {
            next: function() {
                return {
                    value: all[index],
                    done: index++ >= all.length
                }
            }
        }
    }
}

这样在外部就可以使用for...of循环统一去遍历这个todos对象了。这就是实现迭代器的意义,那迭代器这样一个模式他的核心就是对外提供统一遍历接口,让外部不用关心这个数据内部结构是怎样的。只不过这里使用的each方法他只适用于当前这个数据结构而ES2015中的迭代器他是语言层面去实现的迭代器模式。所以说他可以去适用于任何数据结构。只需要你通过代码去实现iterable实现他的逻辑就可以了。

这种模式在很多地方都会用到,只不过很多时候观察都是停留在表象上认为知道某一个api的使用就可以了,根本就不会去关心他内部做的这样一些事情或者忽略掉很多的为什么。

转载须知

如转载必须标明文章出处文章名称文章作者,格式如下:

转自:【致前端 - zhiqianduan.com】 迭代器模式  "隐冬"
请输入评论...