资讯专栏INFORMATION COLUMN

从迭代器模式到迭代协议

doodlewind / 2898人阅读

摘要:迭代器模式迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而不需要暴露该对象的内部表示。可迭代协议和迭代器协议。生成器函数是可以作为迭代器工厂的函数,当它被执行时会返回一个新的对象,该对象符合可迭代协议和迭代器协议。

迭代器模式

迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而不需要暴露该对象的内部表示。

迭代器分为内部迭代器和外部迭代器。内部迭代器只需一次初始调用,而外部迭代器必须显式地请求迭代下一个元素,这样我们就可以手动控制迭代过程。

实现一个内部迭代器:

Array.prototype.innerIterator = function(callback){
    for (let i = 0, len = this.length; i < len; i++) {
        callback && callback.call(this[i], this[i], i)
    }
};
[1,2,3].innerIterator(function(item, index){
    console.log("item:", item, "index:", index)
})
// item: 1 index: 0
// item: 2 index: 1
// item: 3 index: 2

实现一个外部迭代器:

Array.prototype.outerInterator = function(){
    let index = 0;
        return {
            next: () => {
                return index < this.length ?
                {value: this[index++], done: false}:
                {value: undefined, done: true}
            }
    }
}
let iterator = [1,2,3].outerInterator();

for(let next; (next = iterator.next()) && !next.done;) {
    console.log("item", next.value)
}
// item 1
// item 2
// item 3
迭代协议

了解了迭代器模式,再来看看 ES6 中补充的迭代协议。可迭代(iterable)协议和迭代器(iterator)协议。

可迭代协议:
一个可迭代对象(或其原型上),必须有一个 Symbol.iterator 的属性,该属性所对应的值为返回一个对象的无參函数,被返回对象符合迭代器协议。当可迭代对象需要迭代时,调用该方法。

一些数据类型内置了 @@iterator 方法,有自己默认的迭代行为。(String, Array, TypedArray, Map , Set 等都是内置可迭代对象, 因为它们的原型对象都有一个 @@iterator 方法.)([Symbol.iterator]@@iterator 可以认为是一回事

let iterator = ("hi")[Symbol.iterator]()
var a = iterator.next();
// a { value: "h", done: false }

迭代器协议:
一个迭代器必须实现了 next() 方法,该方法是返回一个对象的无參函数。被返回的对象有两个必要的属性:done 和 value。

Array.prototype.Iteration = function(){
    let index = 0;
        return {
            [Symbol.iterator](){return this},
            next: () => {
                return index < this.length ?
                {value: this[index++], done: false}:
                {value: undefined, done: true}
            }
    }
};
let Iteration = [2, 3, 4].Iteration();
for(let value of Iteration) {
    console.log("value", value)
}
// value 2
// value 3
// value 4

不能发现,Iteration 同时满足可迭代协议和迭代协议。又因为是可迭代的,for...of 是可以直接使用,而且这个和外部迭代器十分相似。

一旦一种数据结构有了 @@iterator 方法后, 就认为是可迭代的。ES6 中许多新的方法就是基于此的 解构赋值扩展运算符yield*,还有 for..ofArray.from()等。

知道了以上知识,也就知道了为什么对象不可以直接使用 for...of 了。不过我们可以在对象原型上添加 @@iterator 方法,使之成为可迭代的。

Object.prototype.Iteration = function(){
    let keys = Object.keys(this), index = 0;
        return{
            [Symbol.iterator](){return this},
            next: () => {
                let current = index++;
                return current < keys.length?
                {value: [keys[current], this[keys[current]]], done: false}:
                {value: undefined, done: true};
            }
        }
}
let iterator = {"a": 1, "b": 2, "c": 3}.Iteration();
    for(let [key, value] of iterator) {
        console.log("key:", key, "value:", value)
}
// key: a value: 1
// key: b value: 2
// key: c value: 3
生成器

像以上的的对象都是我们自己手动实现的,符合可迭代协议和迭代协议的对象。看起来很麻烦,还好这些工作已经有函数替我们做了,那就是生成器函数。

生成器函数是可以作为迭代器工厂的函数,当它被执行时会返回一个新的 Generator 对象,该对象符合可迭代协议和迭代器协议。

现在我们用生成器函数使得对象符合迭代协议:

Object.prototype.Iteration = function *(){
    for(let [key, value] of Object.entries(this)){
        yield [key, value]
    }
}
for(let [key, value] of {"a": 1, "b": 2, "c": 3}.Iteration()) {
    console.log("key:", key, "value:", value)
}
// key: a value: 1
// key: b value: 2
// key: c value: 3

在这里生成器只是作为迭代器而已,其实它还是消息双向传递系统。也正是这些特性的存在,使得异步流程控制又向前迈了一大步。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102756.html

相关文章

  • Python标准库---11、内置类型:迭代类型、序列类型(list-typle-range)

    摘要:上一篇文章标准库内置类型数字类型下一篇文章标准库内置类型文本序列类型迭代器类型支持在容器中进行迭代的概念。该对象需要支持下文所述的迭代器协议。这是同时允许容器和迭代器配合和语句使用所必须的。 上一篇文章:Python标准库---10、内置类型:数字类型下一篇文章:Python标准库---12、内置类型:文本序列类型(str) ## 迭代器类型Python 支持在容器中进行迭代的概念。...

    syoya 评论0 收藏0
  • 当谈论迭代时,我谈些什么?

    摘要:示例代码如下此示例中可以看出,当迭代器终止时,通过抛出异常告知迭代器已耗尽。但如果迭代器所指向的数据结构在其存在时发生了插入或删除操作,则迭代器将可能失效。与的情形类似,对进行任何插入操作也将损坏迭代器。 花下猫语:之前说过,我对于编程语言跟其它学科的融合非常感兴趣,但我还说漏了一点,就是我对于 Python 跟其它编程语言的对比学习,也很感兴趣。所以,我一直希望能聚集一些有其它语言基...

    W4n9Hu1 评论0 收藏0
  • 当谈论迭代时,我谈些什么?

    摘要:示例代码如下此示例中可以看出,当迭代器终止时,通过抛出异常告知迭代器已耗尽。但如果迭代器所指向的数据结构在其存在时发生了插入或删除操作,则迭代器将可能失效。与的情形类似,对进行任何插入操作也将损坏迭代器。 花下猫语:之前说过,我对于编程语言跟其它学科的融合非常感兴趣,但我还说漏了一点,就是我对于 Python 跟其它编程语言的对比学习,也很感兴趣。所以,我一直希望能聚集一些有其它语言基...

    王军 评论0 收藏0
  • Python中的可迭代的对象、迭代和生成

    摘要:本文重点掌握可迭代的对象的定义掌握可迭代对象迭代器与生成器之间的关系和异同熟悉标准库中生成器。二迭代器迭代器介绍迭代器用于从集合中取出元素的对象。若想再次迭代须重建迭代器。迭代器检查方式调用,。区别可迭代的对象不是迭代器。 导语:本文章记录了本人在学习Python基础之控制流程篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流。 本文重点: 1、掌握可迭代的对象的...

    starsfun 评论0 收藏0
  • forEach迭代

    摘要:本文从使用对数组进行遍历开始说起,粗略对比使用进行遍历的差异,并由此引入中可迭代对象迭代器的概念,并对其进行粗略介绍。说到这里,就继续说一下迭代器关闭的情况了。确实,符合可迭代协议和迭代器协议的。 本文从使用 forEach 对数组进行遍历开始说起,粗略对比使用 forEach , for...in , for...of 进行遍历的差异,并由此引入 ES6 中 可迭代对象/迭代器 的概...

    rockswang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<