JavaScript中的ES6迭代器

2021-04-01  本文已影响0人  魂斗驴

我们将在本文中分析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实现

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

[ {name: 'Agatha Christie'}, {name: 'J. K. Rowling'}, ... ]

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

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

我们将此方法命名为– iteratorMethod

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

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

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

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

使objects可迭代

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

image.png

可迭代的例子

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

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

JavaScript中的可迭代

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

这些都是可迭代的-

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

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)

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

上一篇下一篇

猜你喜欢

热点阅读