摘要:我们将从概念上理解迭代器是什么,以及在何处使用它们和示例。同时返回一个名为迭代器的对象,这个迭代器将拥有一个名为的方法,该方法将返回一个具有键值为和的对象。下图可以帮助建立可迭代对象迭代器和之间的关系,这种关系称为迭代协议。
我们将在本文中分析迭代器。迭代器是在JavaScript中循环任何集合的一种新方法。它们是在ES6中引入的,由于它们的广泛用途和在不同地方的使用而变得非常流行。
我们将从概念上理解迭代器是什么,以及在何处使用它们和示例。我们还将看到它在JavaScript中的一些实现。如果我问你,你会怎么做?你会说——很简单。我将使用 for、while、for-of 或 其它 方法对它们进行循环。
想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!
简介假设你有这个数组
const myFavouriteAuthors = [ "Neal Stephenson", "Arthur Clarke", "Isaac Asimov", "Robert Heinlein" ];
在某些情况下,希望返回数组中的所有多带带值,以便在屏幕上打印它们、操作它们或对它们执行某些操作。
如下:
现在,假设你拥有一个自定义数据结构来保存所有作者,而不是上面的数组,如:
mypreferteauthors 是一个对象,它包含另一个对象 allAuthors。allAuthors 包含三个数组,其中包含 fiction、scienceFiction 和 fantasy。
现在,如果要求你循环遍历 myFavouriteAuthors 以获得所有的作者,你的方法是什么? 你可能会尝试一些循环组合来获得所有数据。
但是,如果你这样做了 ——
for (let author of myFavouriteAuthors) { console.log(author) } // TypeError: {} is not iterable
你将得到一个类型错误,说明该对象不可迭代。让我们看看什么是可迭代的,以及如何使对象可迭代。
在本文的最后,你将了解如何在定制对象上使用for-of循环,在本例中是在 mypreferteauthors 上使用 for-of 循环。
可迭代对象与迭代器 (Iterables and Iterators)在上一节中看到了问题,从我们的自定义对象中获取所有的作者是不容易的。我们需要某种方法,通过它我们可以有序地获取内部数据。
我们在 mypreferteauthors 中添加一个返回所有作者的方法 getAllAuthors。如:
这是一个简单的方法。它帮我们完成了获取所有作者的功能。但是,这种实现可能会出现一些问题:
getAllAuthors 的名称非常具体。如果其他人正在创建自己的 mypreferteauthors,他们可能会将其命名为retrieveAllAuthors。
作为开发人员,我们总是需要知道返回所有数据的特定方法,在本例中,它被命名为getAllAuthors。
getAllAuthors 返回的是字符串数组,如果另一个开发人员以这种格式返回一个对象数组,该怎么办:
[ {name: "Agatha Christie"}, {name: "J. K. Rowling"}, ... ]
开发人员必须知道返回所有数据的方法的确切名称和返回类型。
如果我们规定方法的名称和它的返回类型是固定不变的呢?
让我们将这个方法命名为 --- iteratorMethod
ECMA 也采取了类似的步骤来标准化在定制对象上循环的过程。但是,ECMA没有使用名称 iteratorMethod,而是使用名称 Symbol.iterator。Symbols 提供的名称是唯一的,不能与其他属性名称冲突。同时,Symbol.iterator 返回一个名为迭代器的对象,这个迭代器将拥有一个名为next的方法,该方法将返回一个具有键值为 value 和 done 的对象。
值键 value 包含当前值,它可以是任何类型的,done 是布尔值,它表示是否获取了所有的值。
下图可以帮助建立可迭代对象、迭代器和next之间的关系,这种关系称为迭代协议。
根据Axel Rauschmayer博士的《探索JS》一书:
可迭代是一种数据结构,它希望使其元素对外部可访问,通过实现一个关键字是Symbol.iterator的方法来实现,该方法是迭代器的工厂,也就是说,它将创建迭代器。
迭代器是一个指针,用于遍历数据结构的元素,我们将使用computed property语法来设置这个键,如下:
建立可迭代对象因此,正如我们在上一节学到的,我们需要实现一个名为Symbol.iterator的方法
在第4行,我们创建迭代器。它是一个定义了next方法的对象。next方法根据step变量返回值。在第25行,我们检索iterator,27行,我们调用next方法,直到 done的值为 true。
这正是for-of循环中发生的事情,for-of接受一个迭代器,并创建它的迭代器,它会一直调用next(),直到 done为 true。
JavaScript中可迭代对象(iterable)JavaScript中的很多对象都是可迭代的。它们可能不是很好的察觉,但是如果仔细检查,就会发现迭代的特征:
Arrays and TypedArrays
Strings —— 遍历每个字符或Unicode代码点
Maps —— 遍历其键-值对
Sets —— 遍历元素
arguments —— 函数中类似数组的特殊变量
DOM elements (Work in Progress)
JS中使用迭代的其他一些结构是:
for-of -- for-of 循环需要一个可迭代的对象,否则,它将抛出一个类型错误。
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 接受可迭代对象
Maps 和 Sets
让 myFavouriteAuthors 可迭代下面是一个实现,它使mypreferteauthors具有可迭代性:
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]() { // 获取数组中的所有作者 const genres = Object.values(this.allAuthors); // 存储当前类型和索引 let currentAuthorIndex = 0; let currentGenreIndex = 0; return { // Implementation of next() next() { // 根据当前的索引获取对应的作者信息 const authors = genres[currentGenreIndex]; // 当遍历完数组 authors是,oNotHaveMoreAuthors 为 true const doNothaveMoreAuthors = !(currentAuthorIndex < authors.length); if (doNothaveMoreAuthors) { // 加一继续访问下一个 currentGenreIndex++; // 重置 currentAuthorIndex = 0; } // 如果所有 genres 都遍历完了结,那么我们需要告诉迭代器不能提供更多的值。 const doNotHaveMoreGenres = !(currentGenreIndex < genres.length); if (doNotHaveMoreGenres) { return { value: undefined, done: true }; } // 如果一切正常,从当genre 返回 作者和当前作者索引,以便下次,下一个作者可以返回。 return { value: genres[currentGenreIndex][currentAuthorIndex++], done: false } } }; } }; for (const author of myFavouriteAuthors) { console.log(author); } console.log(...myFavouriteAuthors)
通过本文获得的知识,你可以很容易地理解迭代器是如何工作的,这种逻辑可能有点难以理解。因此,理解这个概念的最佳方法是多多敲死代码,多多验证!
你的点赞是我持续分享好东西的动力,欢迎点赞!
欢迎加入前端大家庭,里面会经常分享一些技术资源。文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/99601.html
摘要:前言又称提供一个全新的迭代器的概念,它允许我们在语言层面上定义一个有限或无限的序列。后者可以被用来帮助我们理解迭代器。但是当我们使用迭代器时,这个问题就迎刃而解了。是中的新语法,用来配合迭代器。这是因为数组的迭代器只返回其中预期的元素。 前言 EcmaScript 2015 (又称ES6)提供一个全新的迭代器的概念,它允许我们在语言层面上定义一个(有限或无限的)序列。 暂时先抛开它...
摘要:没有显示显示显示关键字迭代器生成器用于马上退出代码块并保留现场,当执行迭代器的函数时,则能从退出点恢复现场并继续执行下去。迭代器迭代器是一个拥有方法和方法的对象,通过函数不断执行以关键字分割的代码段,通过函数令分割的代码段抛出异常。 一、前言 第一次看koajs的示例时,发现该语句 function *(next){..........
摘要:通过生成器创建的迭代器也是可迭代对象,因为生成器默认会为属性赋值。我们可以用来访问对象的默认迭代器,例如对于一个数组获得了数组这个可迭代对象的默认迭代器,并操作它遍历了数组中的元素。 ES6 新的数组方法、集合、for-of 循环、展开运算符(...)甚至异步编程都依赖于迭代器(Iterator )实现。本文会详解 ES6 的迭代器与生成器,并进一步挖掘可迭代对象的内部原理与使用方法 ...
摘要:可迭代对象就具有属性,它是一种与迭代器密切相关的对象。它通过指定的函数可以返回一个作用于附属对象的迭代器。迭代器特点每次调用方法时,返回一个数组,数组中两个元素,分别表示键和值。示例之输出输出输出之迭代器特点返回集合中存在的每一个键。 Iterator由来 不推荐Iterator方法。 Iterator 函数是一个 SpiderMonkey 专有特性,并且会在某一时刻被删除。有一点,需...
阅读 1519·2021-11-17 09:33
阅读 1053·2021-11-12 10:36
阅读 2365·2019-08-30 15:54
阅读 2417·2019-08-30 13:14
阅读 2881·2019-08-26 14:05
阅读 3254·2019-08-26 11:32
阅读 2965·2019-08-26 10:09
阅读 2968·2019-08-26 10:09