es6的迭代器和生成器
迭代器
es6新增的特性,之前没有,其语法借鉴了Python、 Java、 C++。
Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法,可用于迭代List 和 Set 等集合。
实现了迭代器接口的类,都可以使用next方法来取元素。
比如:字符串、数组、映射、集合(Set、Map)、arguments 对象、NodeList 等 DOM 集合类型。
表现
const set = new Set();
set.add('共');
set.add('产');
set.add('党'); const setGen = set[Symbol.iterator](); // 取出迭代器:[Symbol.iterator]创建迭代器的工厂函数
const {done,value:fisrstEl} = setGen.next(); // 调用next取出第一个元素
let hasNext = !done; // 判断有没有元素标识
hasNext && console.log(fisrstEl, hasNext);
while(hasNext){
const {done, value} = setGen.next();
hasNext = !done;
hasNext && console.log(value, hasNext);
}
由上可以推断出:检查是否可以迭代 只需要判断是否存在默认迭代器属性的工厂函数[Symbol.iterator]即可知道
let num = 1;
let obj = {};
let str = 'abc';
// 这两种类型没有实现迭代器工厂函数
console.log(num[Symbol.iterator]); // undefined
console.log(obj[Symbol.iterator]); // undefined
// 这些类型都实现了迭代器工厂函数
console.log(str[Symbol.iterator]); // f values() { [native code] }
自己实现一个迭代器
举例,比如针对Object不支持迭代,所以我们帮其实现一个
const obj = {
    name:'小明',
    age:20,
    [Symbol.iterator](){ // 迭代器工厂函数(用来生成迭代器的)
        let index = 0;
        return {
            next:()=>{
                const v = Object.keys(this)[index++];
                return {done:!Boolean(obj), value:this[v]}
            }
        }
    }
};
const objGen = obj[Symbol.iterator]();
console.log(objGen.next());  // {done: false, value: "小明"}
console.log(objGen.next());  // {done: false, value: 20}
console.log(objGen.next());  // {done: true, value: undefined}
利用生成器来简化迭代器的定义
如上代码,写起来很麻烦,比如我们需要一个index索引,通过自增来确定上一个和下一个。  我们还要写两个嵌套返回等等
所以es为我们提供一个内置办法,可以简化这些操作。
const obj = {
    name:'小明',
    age:20,
    [Symbol.iterator]:function* (){ // 迭代器的生成器(用来取代迭代器工厂函数)
        for (let index = 0; index < Object.keys(this).length; index++) {
            const key =  Object.keys(this)[index];
            yield this[key]
        }
    }
};
const objGen = obj[Symbol.iterator]();
console.log(objGen.next());  // {done: false, value: "小明"}
console.log(objGen.next());  // {done: false, value: 20}
console.log(objGen.next());  // {done: true, value: undefined}
利用生成器来模拟同步代码
yield 关键字可以让生成器停止和开始执行,也是生成器最有用的地方。生成器函数在遇到 yield
关键字之前会正常执行。遇到这个关键字后,执行会停止,函数作用域的状态会被保留。停止执行的生
成器函数只能通过在生成器对象上调用 next()方法来恢复执行
这是红宝书 第4版的话,我们可以利用这个特性来模拟同步ajax
比如我有两个接口,代码如下:
api.js
/*
* 获取老师个人信息
**/
let getTcBasic = (tid) => {
const res = {
1: {
id: 1,
name: '小明',
age: 21,
sex: '男',
twfid: 2001
},
2: {
id: 2,
name: '小蓝',
age: 20,
sex: '男',
twfid: 2002
}
}
return new Promise((resolve) => {
setTimeout(function () {
resolve(res[tid]);
}, 1000);
});
}; /*
* 获取老师配偶信息
**/
const getTcWife = (twfid) => {
const res = {
2001: {
id: 2001,
name: '小红',
age: 18
},
2002: {
id: 2002,
name: '小白',
age: 19
}
}
return new Promise((resolve) => {
setTimeout(function () {
resolve(res[twfid]);
}, 2000);
});
}
实现代码如下
/*
* 循环运行gen(中yield工具 类似于三方包co的作用)
**/
const runGen = (gen, res) => {
const result = gen.next(res);
if (result.done) return;
result.value.then((res) => {
runGen(gen, res);
});
} /*
* 一个含有ajax请求的迭代器实例
* tip: 注意观察写法是不是很同步
**/
function getTcInfoGen(tid){
// 返回generator对象 (generator实例是可以被next分段执行,可以理解为可以分段执行的函数)
const generator = function* (){
console.log('第1次执行');
const tcBasicInfo = yield getTcBasic(tid); console.log('第2次执行');
const tcWifeInfo = yield getTcWife(tcBasicInfo.twfid); console.log('第3次执行');
console.log({...tcBasicInfo,tcWifeInfo});
}
return generator();
} /*
* 获取老师全部信息
**/
const getTcInfo = (tid) => {
console.log('请求中...');
const gen = getTcInfoGen(tid);
runGen(gen)
};
getTcInfo(1);
当然这只是js中同步需求的过度方案,最终还是要使用更加语义化es7中的async和await来  代替 function*和yield。
es7中的async和await是参考 function*和yield并做出了部分改良实现的
虽然Generator将异步操作表示得很简洁,但是流程管理却不方便(即何时执行第一阶段、何时执行第二阶段)。
此时,我们便希望能出现一种能自动执行Generator函数的方法。我们的主角来了async/await。
重新认识一下for...of
for循环的内部机制是:将可迭代对象利用next进行取值,然后将值再给调用者。
这也就意味着只有实现了原生的 iterator 接口,才能使用 for...of。
所以for...of不支持对象迭代。
那我们刚才给对象添加了迭代对象,自然是可以的,运行代码如下
const obj = {
    name:'小明',
    age:20,
    [Symbol.iterator]:function* (){ // 迭代器的生成器(用来取代迭代器工厂函数)
        for (let index = 0; index < Object.keys(this).length; index++) {
            const key =  Object.keys(this)[index];
            yield this[key]
        }
    }
};
for (const iterator of obj) {
    console.log(iterator);
}
// 小明
// 20
相比普通的for循环(也称计数循环),通过迭代器来实现的循环办法更加的方便和自由,因为可以自己实现迭代器,决定结果值。其他好处红宝书第4版所说:
1、迭代之前需要事先知道如何使用数据结构。
2、遍历顺序并不是数据结构固有的
其它
java语言更加完整和系统,所以用java去辅助理解js更加的通俗易懂和完整。
参考java的迭代器相关知识:https://www.runoob.com/java/java-iterator.html
js的集合有哪些?
js集合的概念是在es6中提出的,es5没有 这个概念,同样也是借鉴java等语言进行归纳。
原先可用于存储的有Object和Array,但是这些是有缺点的,至于哪些缺点,自己百度吧。
所以js又发明了新的概念,集合。
Map(以及其子类WeakMap)和Set(以及其子类WeakSet)
贴一张java集合的图

会发现,java的集合更加的全面,这也意味着,JavaScript以后还会对集合进行补充(因为存在这些集合类不是没有道理的,所以同样的js也会面临这些问题。所以慢慢扩充是必然的结果)。
同时也发现集合也都是实现了迭代器接口的。那就意味着集合都是可以迭代的,比如使用next()或者使用for...of。
es6的迭代器和生成器的更多相关文章
- 深入理解ES6之——迭代器与生成器
		
迭代器 迭代器是被设计专用于迭代的对象,带有特定接口.所有的迭代器对象都有next方法,会返回一个结果对象.该结果对象有两个属性:对应下一个值的value,以及一个布尔类型的done,其值为true时 ...
 - 深入理解ES6之迭代器与生成器
		
迭代器 迭代器 iterator,在 Javascript 中,迭代器是一个对象(也可称作为迭代器对象),它提供了一个 next() 方法,用来返回迭代序列中的下一项. next 方法的定义,next ...
 - 【ES6】迭代器与可迭代对象
		
ES6 新的数组方法.集合.for-of 循环.展开运算符(...)甚至异步编程都依赖于迭代器(Iterator )实现.本文会详解 ES6 的迭代器与生成器,并进一步挖掘可迭代对象的内部原理与使用方 ...
 - ES6深入浅出-4 迭代器与生成器-3.生成器 & for...of
		
迭代器平时用的很少.但是如果你是写框架的,你会经常用到迭代器. 生成器是专门用来做迭代器的东西 发布器是要产生一个叫做next的对象,如果你要产生这种对象.就可以使用ES6新出的语法. ES6的新语法 ...
 - 掌握JavaScript中的迭代器和生成器,顺便了解一下async、await的原理
		
掌握JavaScript中的迭代器和生成器,顺便了解一下async.await的原理 前言 相信很多人对迭代器和生成器都不陌生,当提到async和await的原理时,大部分人可能都知道async.aw ...
 - Python 从零学起(纯基础) 笔记 之 迭代器、生成器和修饰器
		
Python的迭代器. 生成器和修饰器 1. 迭代器是访问集合元素的一种方式,从第一个到最后,只许前进不许后退. 优点:不要求事先准备好整个迭代过程中的所有元素,仅仅在迭代到某个元素时才计算该元素,而 ...
 - Python之模块,迭代器与生成器
		
本节涉及内容: 1. 迭代器和生成器 2. 递归 3. 字符串格式化 4. 模块 内置模块 自定义模块 第三方模块 5. 序列化的模块 json pickle (一). 迭代器和生成器: 迭代器: ...
 - Python之迭代器和生成器
		
Python 迭代器和生成器 迭代器 Python中的迭代器为类序列对象(sequence-like objects)提供了一个类序列的接口,迭代器不仅可以对序列对象(string.list.tupl ...
 - python学习笔记四 迭代器,生成器,装饰器(基础篇)
		
迭代器 __iter__方法返回一个迭代器,它是具有__next__方法的对象.在调用__next__方法时,迭代器会返回它的下一个值,若__next__方法调用迭代器 没有值返回,就会引发一个Sto ...
 - 【Python】迭代器、生成器、yield单线程异步并发实现详解
		
转自http://blog.itpub.net/29018063/viewspace-2079767 大家在学习python开发时可能经常对迭代器.生成器.yield关键字用法有所疑惑,在这篇文章将从 ...
 
随机推荐
- java基础之线程池
			
一.线程池:提前创建多个线程存放到集合容器中,其中的线程可以反复使用,减少资源的开销 作用就是:线程执行完一个任务,并不被销毁,而是可以继续执行其他的任务 使用线程池中线程对象的步骤: 1. 创建线程 ...
 - Docker安装elasticsearch、kibana、ik分词器
			
一.下载ealastic search和kibana,两者的版本要一致 docker pull elasticsearch:7.6.2 docker pull kibana:7.6.2 二.配置 mk ...
 - mybatis——分页插件PageHelper的使用
			
项目开发中涉及列表查询时,经常会需要对查询结果进行分页处理:常用的一个插件--PageHelper,是国内非常优秀的一款开源的mybatis分页插件,它支持基本主流与常用的数据库,一致支持mysql. ...
 - MySQL 中使用索引一定有效吗?如何排查索引效果?
			
MySQL 中使用索引一定有效吗?如何排查索引效果? 虽然索引是提升 MySQL 查询性能的常见手段,但并不是所有情况下索引都会有效.索引的使用取决于查询条件.数据分布.索引设计等多个因素.如果索引未 ...
 - mysql免密登录
			
开启mysql免密登录, vi /etc/my.cnf [mysqld]下添加 skip-grant-tables , 保存后重启mysql服务:service mysqld restart
 - 【SQL周周练】一句 SQL 如何帮助 5 个人买到电影院最好的座位?
			
大家好,我是"蒋点数分",多年以来一直从事数据分析工作.从今天开始,与大家持续分享关于数据分析的学习内容. 本文是第 3 篇,也是[SQL 周周练]系列的第 3 篇.该系列是挑选或 ...
 - 反悔贪心&局部调整法学习笔记
			
一.什么是反悔贪心 反悔贪心就是在普通贪心的过程中"反悔",从而使得一些看似不太好贪心的题变成贪心可做题. 二.反悔贪心普遍流程 就是先使用一个好想的贪心策略,使用优先队列进行维护 ...
 - 基于Kubernetes可扩展的Selenium 并行自动化测试部署及搭建(2)——Win10环境下Kubernetes(k8s)部署
			
继续上一篇,本篇进行K8S环境部署. K8s部署: 1. 访问k8s-for-docker-desktop 的github地址: https://github.com/AliyunContainer ...
 - 递归神经网络 RNN 原理(上)
			
前篇对于 RNN 前奏, 或者说是 NLP 的基础, 语言模型 (Language Model) 有了一点认识. LM 的应用场景为 在词库中, 搜索出 符合当前给定 句子的 下一个单词, 的所有可能 ...
 - rancher 卸载后重装报错
			
报错信息 kubectl create namespace cattle-system Error from server (InternalError): Internal error occurr ...