迭代器 (Iterator) 和 生成器 (Generator)
其他章节请看:
迭代器 (Iterator) 和 生成器 (Generator)
试图解决的问题
let colors = ['red', 'blue', 'green', 'yellow']
for(let i = 0, len = colors.length; i < len; i++){
console.log(colors[i])
}
上面是一段标准的 for 循环代码,变过变量 i 来跟踪 colors 的索引,虽然语法简单,但如果将多个循环嵌套则需要跟踪多个变量,代码复杂度会大增,一不小心就错误的使用了其他 for 循环的跟踪变量,导致程序出错。迭代器的出现旨在消除这种复杂性并减少循环中的错误
解决的方法
使用迭代器优化上述问题,请看代码:
let colors = ['red', 'blue', 'green', 'yellow']
for(let color of colors){
console.log(color) // 依次输出:red blue green yellow
}
每个集合(数组、Map和Set)类型都有一个默认的迭代器,在 for-of 循环中,如果没有显示指定则使用默认迭代器
关于迭代器是什么,生成器是什么,这里的数组、for-of和迭代器三者之间的关系又是什么,
所有这些疑问都能在下面的补充章节中找到解答
补充
什么是迭代器
下面我们用 es5 创建一个迭代器:
function createIterator(items){
let i = 0;
let len = items.length;
return {
next: function(){
const result = {
value: items[i],
done: i++ >= len
}
return result;
}
}
}
let iterator = createIterator(['a', 'b', 'c'])
console.log(iterator.next()) // { value: 'a', done: false }
console.log(iterator.next()) // { value: 'b', done: false }
console.log(iterator.next()) // { value: 'c', done: true }
console.log(iterator.next()) // { value: undefined, done: true }
迭代器是一个特殊的对象,它有专门为迭代过程而设计的专有接口,所有的迭代器都有 next() 方法,每次调用 next() 都返回一个结果对象。结果对象有两个属性:一个是value,表示下一个将要返回的值;另一个是done,是一个布尔值类型的值,当没有更多返回数据时返回true
上面这个示例很复杂,es6 中迭代器的编写规则也很复杂,所以 es6 引入生成器,让创建迭代器的过程变得简单
什么是生成器
生成器是一种返回迭代器的函数。通过 function 关键字后面的星号(*)来表示,函数中会用到新的关键字 yield。
下面我们用生成器重写上面的 createIterator() 方法:
// 星号* 可以紧挨着 function 关键字,也可以在中间加空格
function *createIterator(items){
for(let i = 0, len = items.length; i < len; i++){
yield items[i]
}
}
let iterator = createIterator(['a', 'b', 'c'])
console.log(iterator.next()) // { value: 'a', done: false }
console.log(iterator.next()) // { value: 'b', done: false }
console.log(iterator.next()) // { value: 'c', done: false }
console.log(iterator.next()) // { value: undefined, done: true }
createIterator()前面的星号表明它是一个生成器;yield 是 es6 中的新特性,可以通过它来指定调用迭代器的 next() 方法时的返回值和返回顺序。
生成器最有趣的大概是,每次执行完 yield 语句后,函数会自动停止执行。
yield只能在生成器内部使用。下面例子中,从字面上看,yield 确实是在生成器内部,但是它与 return 一样,二者都不能穿透函数边界。
function *createIterator(items){
items.forEach(function(){
yield 1 // 报错
})
}
注:不能用箭头函数创建生成器
可迭代对象和 for-of 循环
首先来回答上面遗留的问题:数组、for-of 和迭代器三者之间的关系是什么?
let colors = ['red', 'blue', 'green', 'yellow']
for(let color of colors){
console.log(color) // 依次输出:red blue green yellow
}
es6中,所有的集合(数组、Map及Set)和字符串都是可迭代对象。一个对象如果有与之对应的迭代器,那么它就是可迭代对象;for-of 循环每执行一次都会调用可迭代对象的 next() 方法,并将迭代器返回的结果对象中的 value 存储在一个变量中,循环将持续到返回对象的 done 属性的值为 true。
三者之间的关系这就很清楚了,数组有自己的迭代器,for-of 会循环迭代器
es6中的可迭代对象具有 Symbol.iterator 属性,执行 Symbol.iterator 指定的函数会返回一个作用于该对象的迭代器,以数组为例:
let arr = [11, 22]
let iterator = arr[Symbol.iterator]()
console.log(iterator.next()) // { value: 11, done: false }
console.log(iterator.next()) // { value: 22, done: false }
console.log(iterator.next()) // { value: undefined, done: true }
注:如果将 for-of 语句用于不可迭代对象、null 或 undefined 将会导致程序报错
内建迭代器
为了更好的访问数据,es6给数组、Set和Map都内建了以下三种迭代器:
- entries() 返回一种迭代器,其值为多个键值对
- values() 返回一种迭代器,其值为集合的所有值
- keys() 返回一种迭代器,其值为集合的所有键名
let arr = [11, 22]
for(let entry of arr.entries()){
// 依次输出:[ 0, 11 ] [ 1, 22 ]
console.log(entry)
}
for(let key of arr.keys()){
// 依次输出:0 1
console.log(key)
}
每种集合都有一个默认的迭代器,在 for-of 循环中,如果没有显示指定则使用默认的迭代器。数组和 Set 的默认迭代器是 values() 方法,Map 的默认迭代器是 entries() 方法
let arr = [11, 22]
for(let value of arr.values()){
// 依次输出:11 22
console.log(value)
}
// 等同于
let arr = [11, 22]
for(let value of arr){
// 依次输出:11 22
console.log(value)
}
自从 es6 添加了迭代器,DOM 中的 NodeList 类型也拥有的默认迭代器,其行为与数组的默认迭代器完全一致
其他章节请看:
迭代器 (Iterator) 和 生成器 (Generator)的更多相关文章
- ES6中的迭代器(Iterator)和生成器(Generator)
前面的话 用循环语句迭代数据时,必须要初始化一个变量来记录每一次迭代在数据集合中的位置,而在许多编程语言中,已经开始通过程序化的方式用迭代器对象返回迭代过程中集合的每一个元素 迭代器的使用可以极大地简 ...
- Python进阶内容(四)--- 迭代器(Iterator)与生成器(Generator)
迭代器 我们已经知道,可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list.tuple.dict.set.str等: 一类是generator,包括生成器和带yield的ge ...
- TypeScript 迭代器(iterator)和生成器(generator)
⒈迭代器(iterator) 1.可迭代性 当一个对象实现了Symbol.iterator属性时,我们认为它是可迭代的. 一些内置的类型如 Array,Map,Set,String,Int32Arra ...
- ES6中的迭代器(Iterator)和生成器(Generator)(一)
用循环语句迭代数据时,必须要初始化一个变量来记录每一次迭代在数据集合中的位置,而在许多编程语言中,已经开始通过程序化的方式用迭代器对象返回迭代过程中集合的每一个元素 迭代器的使用可以极大地简化数据操作 ...
- [TimLinux] Python 迭代器(iterator)和生成器(generator)
1. 可迭代对象 from collection import Iterable class Iterable(metaclass=ABCMeta): ... def __iter__(self): ...
- ES6中的迭代器(Iterator)和生成器(Generator)(二)
一.内建迭代器 迭代器是ES6的一个重要组成部分,在ES6中,已经默认为许多内建类型提供了内建迭代器,只有当这些内建迭代器无法实现目标时才需要自己创建.通常来说当定义自己的对象和类时才会遇到这种情况, ...
- Python的迭代器(iterator)和生成器(constructor)
一.迭代器(iterator) 1.迭代器的概述 在Python中,for循环可以用于Python中的任何类型,包括列表.元祖等等,实际上,for循环可用于任何“可迭代对象”,这其实就是迭代器 迭代器 ...
- Day11 python高级特性-- 迭代器 Iterator
直接可以作用于for循环的数据类型有以下几种: • 集合数据类型: list.tuple.dict.set.str • Generator: 生成器 和 带 y ...
- Python中生成器generator和迭代器Iterator的使用方法
一.生成器 1. 生成器的定义 把所需要值得计算方法储存起来,不会先直接生成数值,而是等到什么时候使用什么时候生成,每次生成一个,减少计算机占用内存空间 2. 生成器的创建方式 第一种只要把一个列表生 ...
随机推荐
- H - 看病要排队
看病要排队这个是地球人都知道的常识.不过经过细心的0068的观察,他发现了医院里排队还是有讲究的.0068所去的医院有三个医生(汗,这么少)同时看病.而看病的人病情有轻重,所以不能根据简单的先来先服务 ...
- G - 棋盘游戏
小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的"车",并且使得他们不能互相攻击,这当然很简单,但是Gardon限制了只有某些格子才可以放, ...
- HDU5740 Glorious Brilliance【最短路 KM匹配】
HDU5740 Glorious Brilliance 题意: 给出一张不一定合法的染色图,每次可以交换相邻两点的颜色,问最少多少次能使染色图合法 合法的染色图相邻点的颜色不能相同 题解: 首先要确定 ...
- Codeforces Round #135 (Div. 2) D. Choosing Capital for Treeland
time limit per test 3 seconds memory limit per test 256 megabytes input standard input output standa ...
- 使用开源量子编程框架ProjectQ打印编译后的量子线路与绘制线路图
技术背景 在量子计算领域,基于量子芯片的算法设计(或简称为量子算法)是基于量子线路来设计的,类似于传统计算中使用的与门和非门之类的逻辑门.因此研究一个量子线路输入后的编译(可以简化为数量更少的量子门组 ...
- MySQL菜鸟实录(一):MySQL服务安装实战
CentOS 7 基本信息 系统版本: CentOS 7.3 64bit 系统配置: 4vCPUs | 8GB 磁盘空间: [root@ecs-ce5a-0001 ~]# df -h Filesyst ...
- 数学知识-欧拉函数&快速幂
欧拉函数 定义 对于正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目,记作φ(n). 算法思路 既然求解每个数的欧拉函数,都需要知道他的质因子,而不需要个数 因此,我们只需求出他的质因子, ...
- PHP的常用函数 持续更新
PHP的常用函数 前言: 由于害怕遗忘,故在此记录下常用的php函数,以便复习 1 define函数 作用:定义常量 用法 <?php define('a',100); ?> 2 intv ...
- Redis Cluster 分布式集群(下)
Redis Cluster 搭建(工具) 环境准备 节点 IP 端口 节点① 172.16.1.121 6379,6380 节点② 172.16.1.122 6379,6380 节点③ 172.16. ...
- Os-hackNos-1(drupal7+suid提权)
一.信息收集 得到 ip是 192.168.56.101 , 端口开启了22和80,扫目录发现drupal 7 访问一下呢 在exploit-db上面搜索到存在相关的漏洞,而且是用直接上msf 使用第 ...