JavaScript中的ES6迭代器

我们将在本文中分析Iterators。迭代器是一种遍历JavaScript中任何Set的新方法。它们是在ES6中引入的,并已变得非常流行自从 它们广泛有用,并在各个地方使用。

我们将在概念上理解什么是迭代器以及在示例中将其使用在何处。我们还将看到它在JavaScript中的一些实现。

介绍

假设您有这个数组-

const myFavouriteAuthors = [
  'Neal Stephenson',
  'Arthur Clarke',
  'Isaac Asimov', 
  'Robert Heinlein'
];

在某个时候,您将需要取回数组中的所有单个值,以便在屏幕上打印它们,对其进行操作或对它们执行某些操作。如果我问你,你会怎么做?您会说-这很容易。我就对他们循环中使用forwhilefor-of或一个这些循环的方法。 示例实现为—

数组上的各种循环技术

现在,假设您有一个自定义数据结构来容纳所有作者,而不是前面的数组。像这样 -

自定义数据结构

现在,myFavouriteAuthors是一个包含另一个object的对象allAuthorsallAuthors包含三个阵列,对应key是fictionscienceFictionfantasy现在,如果我要您遍历myFavouriteAuthors所有作者,您的做法是什么? 您可以继续尝试一些循环组合以获取所有数据。

但是,如果您这样做-

for (let author of myFavouriteAuthors) { 
  console.log(author)
}
// TypeError: {} is not iterable

你会得到一个TypeError说法,那就是对象是不可迭代的让我们看看什么是可迭代的,以及如何使对象可迭代的。 在本文的最后,您将了解如何for-of在自定义对象(在本例中为on)上使用循环myFavouriteAuthors

可迭代和迭代器

您在上一节中看到了问题。没有简单的方法可以从我们的自定义对象中获取所有作者。我们需要一种方法,通过该方法可以顺序公开所有内部数据。

让我们添加一个方法getAllAuthorsmyFavouriteAuthors返回所有作者。像这样 -

getAllAuthors实现

这是一种简单的方法。它完成了我们当前吸引所有作者的任务。但是,此实现可能会出现一些问题。他们之中有一些是 -

  • 这个名字getAllAuthors很具体。如果别人创造了自己的myFavouriteAuthors名字,他们可以给它命名retrieveAllAuthors
  • 作为开发人员,我们始终需要了解将返回所有数据的特定方法。在这种情况下,它名为getAllAuthors
  • getAllAuthors返回所有作者的字符串数组。如果另一个开发人员以这种格式返回对象数组怎么办?
[ {name: 'Agatha Christie'}, {name: 'J. K. Rowling'}, ... ]

开发人员将必须知道返回所有数据的方法的确切名称和返回类型

如果我们制定一个规则来确定方法的名称及其返回类型 将是固定且不可更改的,该怎么办?

我们将此方法命名为– iteratorMethod

ECMA采取了类似的步骤来标准化循环遍历自定义对象的过程。但是,iteratorMethodECMA使用名称代替了名称Symbol.iteratorSymbols提供的名称是唯一的,并且不能与其他属性名称冲突。同样,Symbol.iterator返回一个称为iterator的对象 。此迭代器将具有称为的方法next,该方法将返回带有键value和的对象done

value密钥将包含当前值。它可以是任何类型。的done是布尔值。它表示是否已获取所有值。

图解可以帮助建立关系iterables迭代器,和next这种关系称为迭代协议。

可迭代,迭代和下一步之间的关系。

  • 一个迭代是想让它的元素向公众开放的数据结构。它是通过实现一个key为Symbol.iterator的方法来实现的。该方法是迭代器的工厂。也就是说,它将创建迭代器
  • 一个迭代器是用于遍历数据结构的元素的指针。

使objects可迭代

因此,正如我们在上一节中了解到的那样,我们需要实现一种称为Symbol.iterator的方法。我们将使用计算属性语法来设置此键。一个简短的例子是-

image.png

可迭代的例子

在第4行,我们进行迭代。这是一个已next定义方法的对象。该next方法根据step变量返回值。在第25行,我们检索iterator。我们于27日致电next。我们一直打电话给下一位,直到done成为true

这正是for-of循环发生的情况。该for-of循环需要一个迭代,并创建它的迭代器。它一直在调用next()直到直到done为真。

JavaScript中的可迭代

JavaScript中有很多事情是可迭代的。它可能不会立即可见,但是如果仔细检查,可迭代项将开始显示。

这些都是可迭代的-

  • 数组TypedArrays
  • 字符串-遍历每个字符或Unicode代码点。
  • Map-遍历其键值对
  • Set-遍历其元素
  • arguments —函数中类似数组的特殊变量
  • DOM元素

JS中使用可迭代对象的其他一些构造是-

  • for-of循环-在for-of循环需要一个迭代。否则,它将抛出TypeError
for (const value of iterable) { ... }
  • 数组的解构—因为可迭代,所以发生解构。让我们看看如何。

代码

const array = ['a', 'b', 'c', 'd', 'e'];
const [first, ,third, ,last] = array;

相当于

const array = ['a', 'b', 'c', 'd', 'e'];
const iterator = array[Symbol.iterator]();
const first = iterator.next().value
iterator.next().value // Since it was skipped, so it's not assigned
const third = iterator.next().value
iterator.next().value // Since it was skipped, so it's not assigned
const last = iterator.next().value
  • 解构运算符(…)

代码

const array = ['a', 'b', 'c', 'd', 'e'];
const newArray = [1, ...array, 2, 3];

可以写成

const array = ['a', 'b', 'c', 'd', 'e'];
const iterator = array[Symbol.iterator]();
const newArray = [1];
for (let nextValue = iterator.next(); nextValue.done !== true; nextValue = iterator.next()) {
  newArray.push(nextValue.value);
}
newArray.push(2)
newArray.push(3)
  • Promise.allPromise.race在Promises上接受可迭代项。
  • Map和Set

Map的构造函数将可迭代的over[key, value]对转换为Map,而Set的构造函数将可迭代的over元素转换为Set-

const map = new Map([[1, 'one'], [2, 'two']]);
map.get(1) 
// one
const set = new Set(['a', 'b', 'c]);
set.has('c');
// true
  • 迭代器也是了解生成器功能的前提。

使myFavouriteAuthors可迭代

这是一个myFavouriteAuthors可迭代的实现。

const myFavouriteAuthors = {
  allAuthors: {
    fiction: [
      'Agatha Christie', 
      'J. K. Rowling',
      'Dr. Seuss'
    ],
    scienceFiction: [
      'Neal Stephenson',
      'Arthur Clarke',
      'Isaac Asimov', 
      'Robert Heinlein'
    ],
    fantasy: [
      'J. R. R. Tolkien',
      'J. K. Rowling',
      'Terry Pratchett'
    ],
  },
  [Symbol.iterator]() {
    // Get all the authors in an array
    const genres = Object.values(this.allAuthors);
    
    // Store the current genre and author index
    let currentAuthorIndex = 0;
    let currentGenreIndex = 0;
    
    return {
      // Implementation of next()
      next() {
        // authors according to current genre index
        const authors = genres[currentGenreIndex];
        
        // doNotHaveMoreAuthors is true when the authors array is exhausted.
        // That is, all items are consumed.
        const doNothaveMoreAuthors = !(currentAuthorIndex < authors.length);
        if (doNothaveMoreAuthors) {
          // When that happens, we move the genre index to the next genre
          currentGenreIndex++;
          // and reset the author index to 0 again to get new set of authors
          currentAuthorIndex = 0;
        }
        
        // if all genres are over, then we need tell the iterator that we 
        // can not give more values.
        const doNotHaveMoreGenres = !(currentGenreIndex < genres.length);
        if (doNotHaveMoreGenres) {
          // Hence, we return done as true.
          return {
            value: undefined,
            done: true
          };
        }
        
        // if everything is correct, return the author from the 
        // current genre and incerement the currentAuthorindex
        // so next time, the next author can be returned.
        return {
          value: genres[currentGenreIndex][currentAuthorIndex++],
          done: false
        }
      }
    };
  }
};

for (const author of myFavouriteAuthors) {
  console.log(author);
}

console.log(...myFavouriteAuthors)

可迭代的示例实现

利用从本文中获得的知识,您可以轻松地了解迭代器的工作方式。该逻辑可能有点难以遵循。因此,我已经用代码编写了注释。但是,内化和理解该概念的最佳方法是在浏览器或节点中使用代码。

参考

A Simple Guide to ES6 Iterators in JavaScript with Examples

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容