JavaScript中的ES6迭代器
我们将在本文中分析Iterators。迭代器是一种遍历JavaScript中任何Set的新方法。它们是在ES6中引入的,并已变得非常流行自从 它们广泛有用,并在各个地方使用。
我们将在概念上理解什么是迭代器以及在示例中将其使用在何处。我们还将看到它在JavaScript中的一些实现。
介绍
假设您有这个数组-
const myFavouriteAuthors = [
'Neal Stephenson',
'Arthur Clarke',
'Isaac Asimov',
'Robert Heinlein'
];
在某个时候,您将需要取回数组中的所有单个值,以便在屏幕上打印它们,对其进行操作或对它们执行某些操作。如果我问你,你会怎么做?您会说-这很容易。我就对他们循环中使用for
,while
,for-of
或一个这些循环的方法。 示例实现为—
数组上的各种循环技术
现在,假设您有一个自定义数据结构来容纳所有作者,而不是前面的数组。像这样 -
自定义数据结构
现在,myFavouriteAuthors
是一个包含另一个object的对象allAuthors
。allAuthors
包含三个阵列,对应key是fiction
,scienceFiction
和fantasy
。 现在,如果我要您遍历myFavouriteAuthors
所有作者,您的做法是什么? 您可以继续尝试一些循环组合以获取所有数据。
但是,如果您这样做-
for (let author of myFavouriteAuthors) {
console.log(author)
}
// TypeError: {} is not iterable
你会得到一个TypeError
说法,那就是对象是不可迭代的。让我们看看什么是可迭代的,以及如何使对象可迭代的。 在本文的最后,您将了解如何for-of
在自定义对象(在本例中为on)上使用循环myFavouriteAuthors
。
可迭代和迭代器
您在上一节中看到了问题。没有简单的方法可以从我们的自定义对象中获取所有作者。我们需要一种方法,通过该方法可以顺序公开所有内部数据。
让我们添加一个方法getAllAuthors
中myFavouriteAuthors
返回所有作者。像这样 -
getAllAuthors实现
这是一种简单的方法。它完成了我们当前吸引所有作者的任务。但是,此实现可能会出现一些问题。他们之中有一些是 -
- 这个名字
getAllAuthors
很具体。如果别人创造了自己的myFavouriteAuthors
名字,他们可以给它命名retrieveAllAuthors
。 - 作为开发人员,我们始终需要了解将返回所有数据的特定方法。在这种情况下,它名为
getAllAuthors
。 -
getAllAuthors
返回所有作者的字符串数组。如果另一个开发人员以这种格式返回对象数组怎么办?
[ {name: 'Agatha Christie'}, {name: 'J. K. Rowling'}, ... ]
开发人员将必须知道返回所有数据的方法的确切名称和返回类型。
如果我们制定一个规则来确定方法的名称及其返回类型 将是固定且不可更改的,该怎么办?
我们将此方法命名为– iteratorMethod。
ECMA采取了类似的步骤来标准化循环遍历自定义对象的过程。但是,iteratorMethod
ECMA使用名称代替了名称Symbol.iterator
。Symbols提供的名称是唯一的,并且不能与其他属性名称冲突。同样,Symbol.iterator
将返回一个称为iterator
的对象 。此迭代器将具有称为的方法next
,该方法将返回带有键value
和的对象done
。
该value
密钥将包含当前值。它可以是任何类型。的done
是布尔值。它表示是否已获取所有值。
图解可以帮助建立关系iterables,迭代器,和next。这种关系称为迭代协议。
可迭代,迭代和下一步之间的关系。
- 一个迭代是想让它的元素向公众开放的数据结构。它是通过实现一个key为
Symbol.iterator
的方法来实现的。该方法是迭代器的工厂。也就是说,它将创建迭代器。 - 一个迭代器是用于遍历数据结构的元素的指针。
使objects
可迭代
因此,正如我们在上一节中了解到的那样,我们需要实现一种称为Symbol.iterator
的方法。我们将使用计算属性语法来设置此键。一个简短的例子是-
可迭代的例子
在第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.all
并Promise.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)
可迭代的示例实现
利用从本文中获得的知识,您可以轻松地了解迭代器的工作方式。该逻辑可能有点难以遵循。因此,我已经用代码编写了注释。但是,内化和理解该概念的最佳方法是在浏览器或节点中使用代码。