简单理解迭代器模式

172天前 · 代码 · 297次阅读

这几天研究了一下迭代器模式,期间有一段时间经常搞不太懂一些概念与概念之间的关系,今天来整理一下。

迭代的一些基本概念

  1. 循环是迭代机制的基础
  2. 迭代在一个有序集合上进行
  3. 按照顺序反复多次执行一段程序,通常会有明确的终止条件

我的理解:

实际上就是为了优化循环,各种数据结构的循环。而且各种数据结构循环起来可以千奇百怪,为了合理的统一,就有了迭代器模式。

关键词

  • 可迭代对象
  • 可迭代协议(Iterable接口)
  • 迭代器
  • 迭代器协议(Iterator接口)
  • 迭代器对象( IteratorResult

关系图

QA式学习

Q:什么是可迭代对象?

A:满足可迭代协议(实现Iterable接口)的对象。

Q:可迭代协议是啥?

A:就是Iterable接口。满足可迭代协议的对象应该满足以下条件:

  1. 能够创建实现了Iterator接口的对象(实际上就是迭代器)
  2. 且可以通过迭代器Iterator消费。

举个例子,数组,集合,映射等等都满足可迭代协议。他们都可以用for...of遍历。

Q:什么是消费?

A:可以理解为遍历。有一个相关的概念“耗尽”,可以理解为遍历结束了。

Q:怎么满足可迭代协议?

A:你的对象需要有一个键名为Symbol.iterator的属性,指向一个迭代器工厂函数。啥意思嘞?就是说

//jojo是一个可迭代对象(数组)
console.log(jojo[Symbol.iterator]); // ƒ values() { [native code] }

作为一个工厂函数,我们调用它的话就应该可以生成一个迭代器

console.log(jojo[Symbol.iterator]()); //Array Iterator {}

Q:什么是迭代器?

A:首先,迭代器是用于迭代与其关联的对象的一次性使用对象,迭代器满足迭代器协议(实现Iterator接口)。一次性是指其在完成一次遍历(消费)之后就会被“耗尽”,这个时候再想遍历只能通过重新生成一个迭代器。

Q:迭代器协议说了啥?

A:迭代器协议说,只要你实现了Iterator接口,你就是个迭代器辣!你至少需要有一个next()方法来返回一个迭代器对象IteratorResult。这个对象包含两个属性:donevalue。其中done为一个布尔值,当done不为真时表示还可以通过调用next()取得下一个值,当done为真时,就可以被称为“耗尽”了。当done不为真时,value对象表示可迭代对象的下一个值,而当done不为真时,value就自然为undefined了。

模拟for...of

在MDN上有这么一段话

The for...of statement creates a loop iterating over iterable objects, including: built-in String, Array, array-like objects (e.g., arguments or NodeList), TypedArray, Map, Set, and user-defined iterables.

大意

for...of语句为可迭代对象创建循环迭代。这些可迭代对象包括内置的StringArray,和一些类数组对象(比如argumentsNodeList),TypedArrayMapSet和用户定义的可迭代对象。

也就是说实际上使用for...of来遍历正是迭代器模式的一个应用。通过模拟一个数组的for...of遍历来更好地理解一下迭代器。

当我们普普通通for..of的时候发生了甚么事呢?

let arr = [1,2,3,4,5];

for(let item of arr)
    console.log(item);

实际上上面的代码可以等价于下面的代码。

let arr = [1,2,3,4,5];

let it = arr[Symbol.iterator]();//it->迭代器,通过调用arr[Symbol.iterator]()来生成
let item = it.next();//item->迭代器对象,包含着done和value两个属性
while(!item.done) {//当迭代器没有耗尽时
    console.log(item.value);//可以通过item.value来访问当前迭代到的值
    item = it.next();//继续迭代
}

自定义迭代器

刚刚提到了,for...of同样可以用于遍历用户定义的可迭代对象。一般的可迭代对象是不可以用for...of来遍历的,但是我们可以通过改造我们的对象,使其满足可迭代协议来使用for...of

let colors = {
    blue : "蓝色",
    green : "绿色",
    yellow : "黄色"
};
for(let color of colors)
    console.log(color);

尖尖达咩

现在我们让color对象满足Iterable接口

colors[Symbol.iterator] = function() {
    let keys = Object.keys(colors);
    let index = 0;
    return {
        next : function() {
            if (index < keys.length) {
                return {
                    value : colors[keys[index++]],
                    done : false
                }
            }
            return { done : true }
        }
    }
}

然后再次for...of循环,可以发现没有报错,并且正常循环输出了。

成功辽

以上就是我对迭代器的一些理解,如果有什么问题欢迎指正!

👍 14

js 迭代器

最后修改于171天前

评论

贴吧 狗头 原神 小黄脸
收起

贴吧

狗头

原神

小黄脸

  1. qinians 162天前

    感谢

  2. Hêlli 163天前

    Hello

    1. 季悠然 162天前

      Guten Tag

  3. 165天前

    谢谢分享!

目录

avatar

季悠然

寻找有趣的灵魂

127

文章数

1954

评论数

3

分类

好热啊

arknights!

失去人性,失去很多;失去兽性,失去一切。

刘慈欣

107