详解简单易懂的 ES6 Iterators 指南和示例


Posted in Javascript onSeptember 24, 2019

本文旨在分析理解 Iterators。 Iterators 是 JS中的新方法,可以用来循环任意集合。 在ES6中登场的Iterators。因其可被广泛使用,并且已在多处场景派上用场,我们将从概念上理解迭代器是什么,以及在何处使用它们和示例。我们还将看到它在JS 中的一些实现。

简介

假设有这样数组

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

在某些情况下,希望返回数组中的所有单独值,以便在屏幕上打印它们、操作它们或对它们执行某些操作。

如何处理? 简单方法就是使用 for, while, for-of 方法。

如下:

详解简单易懂的 ES6 Iterators 指南和示例

现在,假设你拥有一个自定义数据结构来保存所有authors

详解简单易懂的 ES6 Iterators 指南和示例

myFavouriteAuthors 是一个对象,它包含另一个对象 allAuthorsallAuthors 包含三个数组,其中包含 fictionscienceFictionfantasy

现在,如果要求你循环遍历 myFavouriteAuthors 以获得所有的author,你的方法是什么? 你可能会尝试一些循环组合来获得所有数据。

但是,如果你这样做了 ——

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

你将得到一个类型错误,说明该对象不可迭代。让我们看看什么是可迭代的,以及如何使对象可迭代。

可迭代对象与迭代器 (Iterables and Iterators)

在上一节中看到了问题,从我们的自定义对象中获取所有的author 是不容易的。我们需要某种方法,通过它我们可以有序地获取内部数据。

我们在 myFavouriteAuthors 中添加一个返回所有作者的方法 getAllAuthors。如:

详解简单易懂的 ES6 Iterators 指南和示例

这是一个简单的方法。它帮我们完成了获取所有author的功能。但是,这种实现可能会出现一些问题:

  • getAllAuthors 的名称非常具体。如果其他人正在创建自己的 myFavouriteAuthors,他们可能会将其命名为retrieveAllAuthors
  • 作为开发人员,我们总是需要知道返回所有数据的特定方法,在本例中,它被命名为getAllAuthors
  • getAllAuthors 返回的是字符串数组,如果另一个开发人员以这种格式返回一个对象数组,该怎么办:
[ {name: 'Agatha Christie'}, {name: 'J. K. Rowling'}, ... ]

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

如果我们规定方法的名称和它的返回类型是固定不变的呢?

让我们将这个方法命名为 --- iteratorMethod

ECMA 也采取了类似的步骤来标准化在定制对象上循环的过程。但是,ECMA 没有使用名称 iteratorMethod,而是使用名称 Symbol.iterator。

Symbols 提供的名称是唯一的,不能与其他属性名称冲突。同时,Symbol.iterator 返回一个名为迭代器的对象,这个迭代器将拥有一个名为next的方法,该方法将返回一个具有键值为 valuedone 的对象。

值键 value 包含当前值,它可以是任何类型的,done 是布尔值,它表示是否获取了所有的值。

下图可以帮助建立可迭代对象、迭代器和next之间的关系,这种关系称为迭代协议。

详解简单易懂的 ES6 Iterators 指南和示例

根据Axel Rauschmayer博士的《探索JS》一书:

可迭代是一种数据结构,它希望使其元素对外部可访问,通过实现一个关键字是Symbol.iterator的方法来实现,该方法是迭代器的工厂,也就是说,它将创建迭代器。迭代器是一个指针,用于遍历数据结构的元素,我们将使用computed property语法来设置这个键,如下:

使用对象可迭代

因此,正如我们在上一节学到的,我们需要实现一个名为Symbol.iterator的方法

详解简单易懂的 ES6 Iterators 指南和示例

在第4行,我们创建迭代器。它是一个定义了next方法的对象。next方法根据step变量返回值。在第25行,我们检索iterator,27 行,我们调用next方法,直到 done的值为 true。

这正是for-of循环中发生的事情,for-of接受一个迭代器,并创建它的迭代器,它会一直调用next(),直到 done为 true。

JavaScript中可迭代对象(iterable)

JS 中的很多对象都是可迭代的。它们可能不是很好的察觉,但是如果仔细检查,就会发现迭代的特征:

  • 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.allPromise.race 接受可迭代对象

Maps 和 Sets

让 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]() {
  // 获取数组中的所有作者
  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)

通过本文获得的知识,你可以很容易地理解迭代器是如何工作的,这种逻辑可能有点难以理解。因此,理解这个概念的最佳方法是多多敲死代码,多多验证!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JQUERY THICKBOX弹出层插件
Aug 30 Javascript
实例代码讲解jquery easyui动态tab页
Nov 17 Javascript
浅谈JavaScript事件绑定的常用方法及其优缺点分析
Nov 01 Javascript
js实现文字无缝向上滚动
Feb 16 Javascript
JS去掉字符串前后空格或去掉所有空格的用法
Mar 25 Javascript
微信小程序图片自适应支持多图实例详解
Jun 21 Javascript
Vue实现双向绑定的原理以及响应式数据的方法
Jul 02 Javascript
微信小程序使用swiper组件实现层叠轮播图
Nov 04 Javascript
ES6知识点整理之对象解构赋值应用示例
Apr 17 Javascript
ES6中Symbol、Set和Map用法详解
Aug 20 Javascript
浅谈webpack和webpack-cli模块源码分析
Jan 19 Javascript
js中!和!!的区别与用法
May 09 Javascript
layui实现下拉复选功能的例子(包括数据的回显与上传)
Sep 24 #Javascript
基于layui的下拉列表的数据回显方法
Sep 24 #Javascript
Layui动态生成select下拉选择框不显示的解决方法
Sep 24 #Javascript
layui动态渲染生成select的option值方法
Sep 23 #Javascript
微信小程序全局变量GLOBALDATA的定义和调用过程解析
Sep 23 #Javascript
layui-select动态选中值的例子
Sep 23 #Javascript
layui多图上传实现删除功能的例子
Sep 23 #Javascript
You might like
FCKeditor的安装(PHP)
2007/01/13 PHP
UTF-8正则表达式如何匹配汉字
2015/08/03 PHP
PHP响应post请求上传文件的方法
2015/12/17 PHP
php实现在站点里面添加邮件发送的功能
2020/04/28 PHP
WordPress分页伪静态加html后缀
2016/06/08 PHP
PHP设计模式之委托模式定义与用法简单示例
2018/08/13 PHP
关于jQuery object and DOM element
2013/04/15 Javascript
jquery ajax传递中文参数乱码问题及解决方法说明
2014/02/07 Javascript
javascript实现节点(div)名称编辑
2014/12/17 Javascript
javascript瀑布流式图片懒加载实例解析与优化
2016/02/23 Javascript
Vuejs第十篇之vuejs父子组件通信
2016/09/06 Javascript
js实现表单及时验证功能 用户信息立即验证
2016/09/13 Javascript
详解webpack的配置文件entry与output
2017/08/21 Javascript
详解Vue内部怎样处理props选项的多种写法
2018/11/06 Javascript
使用Javascript简单计算器
2018/11/17 Javascript
[00:37]DOTA2上海特级锦标赛 OG战队宣传片
2016/03/03 DOTA
[12:21]VICI vs TNC (BO3)
2018/06/07 DOTA
WINDOWS 同时安装 python2 python3 后 pip 错误的解决方法
2017/03/16 Python
python3.4.3下逐行读入txt文本并去重的方法
2018/04/29 Python
python中update的基本使用方法详解
2019/07/17 Python
python 实现生成均匀分布的点
2019/12/05 Python
使用python turtle画高达
2020/01/19 Python
使用Pycharm分段执行代码
2020/04/15 Python
opencv-python的RGB与BGR互转方式
2020/06/02 Python
python编程的核心知识点总结
2021/02/08 Python
东方电视购物:东方CJ
2016/10/12 全球购物
Proenza Schouler官方网站:纽约女装和配饰品牌
2019/01/03 全球购物
数控专业个人求职信范例
2013/11/29 职场文书
计算机大学生职业生涯规划书范文
2014/02/19 职场文书
中学生励志演讲稿
2014/04/26 职场文书
伦敦奥运会口号
2014/06/13 职场文书
审计班子对照检查材料
2014/08/27 职场文书
大学生国庆节65周年演讲稿范文
2014/09/25 职场文书
学校国庆节活动总结
2015/03/23 职场文书
学生会部长竞选稿
2015/11/19 职场文书
中学教代会开幕词
2016/03/04 职场文书