详解简单易懂的 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 相关文章推荐
用js实现判断当前网址的来路如果不是指定的来路就跳转到指定页面
May 02 Javascript
jQuery源码分析-02正则表达式 RegExp 常用正则表达式
Nov 14 Javascript
ES6中非常实用的新特性介绍
Mar 10 Javascript
分享jQuery网页元素拖拽插件
Dec 01 Javascript
JavaScript中Array的实用操作技巧分享
Sep 11 Javascript
AngularJS表单基本操作
Jan 09 Javascript
Angular.js自定义指令学习笔记实例
Feb 24 Javascript
jQuery插件echarts实现的多折线图效果示例【附demo源码下载】
Mar 04 Javascript
jquery获取file表单选择文件的路径、名字、大小、类型
Jan 18 jQuery
小程序云开发之用户注册登录
May 18 Javascript
javascript 高级语法之继承的基本使用方法示例
Nov 11 Javascript
react组件基本用法示例小结
Apr 27 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
php 进度条实现代码
2009/03/10 PHP
获取页面高度,窗口高度,滚动条高度等参数值getPageSize,getPageScroll
2006/09/22 Javascript
JavaScript中的常见问题解决方法(乱码,IE缓存,代理)
2013/11/28 Javascript
JQuery each()嵌套使用小结
2014/04/18 Javascript
jQuery窗口、文档、网页各种高度的精确理解
2014/07/02 Javascript
使用node.js 制作网站前台后台
2014/11/13 Javascript
javascript实现实时输出当前的时间
2015/04/27 Javascript
jQuery拖动布局其结果保存到数据库
2015/10/09 Javascript
Express的路由详解
2015/12/10 Javascript
JavaScript优化专题之Loading and Execution加载和运行
2016/01/20 Javascript
JS实现CheckBox复选框全选、不选或全不选功能
2020/07/28 Javascript
基于javascript实现泡泡大冒险网页版小游戏
2016/03/23 Javascript
JavaScript通过HTML的class来获取HTML元素的方法总结
2016/05/24 Javascript
js实现可控制左右方向的无缝滚动效果
2016/05/29 Javascript
概述jQuery的元素筛选
2016/11/23 Javascript
Jquery给当前页或者跳转后页面的导航栏添加选中后样式的实例
2016/12/08 Javascript
jQuery Ajax File Upload实例源码
2016/12/12 Javascript
js仿拉勾网首页穿墙广告效果
2017/03/08 Javascript
Bootstrap Table使用整理(四)之工具栏
2017/06/09 Javascript
JS数组求和的常用方法实例小结
2019/01/07 Javascript
python根据txt文本批量创建文件夹
2020/12/08 Python
python 非线性规划方式(scipy.optimize.minimize)
2020/02/11 Python
Python日志器使用方法及原理解析
2020/09/27 Python
anaconda安装pytorch1.7.1和torchvision0.8.2的方法(亲测可用)
2021/02/01 Python
html5 兼容IE6结构的实现代码
2012/05/14 HTML / CSS
印度第一网上礼品店:IGP.com
2020/02/06 全球购物
Lentiamo丹麦:购买便宜的隐形眼镜
2021/01/13 全球购物
怎样声明接口
2014/09/19 面试题
农业局学习党的群众路线教育实践活动心得体会
2014/03/07 职场文书
模具设计与制造专业自荐书
2014/07/01 职场文书
幼儿园清明节活动总结
2014/07/04 职场文书
2014年医院科室工作总结
2014/12/20 职场文书
给老婆的保证书
2015/01/16 职场文书
2015年度工程师评职称工作总结
2015/10/14 职场文书
2015年高三毕业班班主任工作总结
2015/10/22 职场文书
解决Python字典查找报Keyerror的问题
2021/05/26 Python