JavaScript的迭代器与生成器
迭代器与生成器
- 迭代器
- 什么是迭代器?
- 可迭代对象
- 原生迭代器对象
- 可迭代对象的应用
- 自定义类的迭代
- 生成器
- 什么是生成器?
- 生成器传递参数-next函数
- 生成器替代迭代器
迭代器
什么是迭代器?
迭代器(iterator),是确使用户可在容器对象(container,例如链表或数组)上遍访的对象,使用该接口无需关系对象的内部实现细节。
其行为像数据库中的光标,迭代器最早出现在1974年设计的CLU编程语言中;
在各种编程语言的实现中,迭代器的实现方式各不相同,但是基本都有迭代器,比如Java,Python等;
在迭代器的定义我们可以看出来,迭代器是帮助我们对某个数据结构进行遍历的对象
在Javascript中,迭代器也是一个具体的对象,这个对象需要符合迭代器协议(iterator protocol);
迭代器协议定义了产生一系列值(无论是有限还是无限个) 的标准方式;
那么在js中这个标准就是一个特定的next方法;
next方法有如下的要求:
一个无参数或者一个参数的函数,返回一个应当拥有以下两个属性的对象:
done(boolean)
- 如果迭代器可以产生序列中的下一个值,则为false。(这等价于没有指定done这个属性)
- 如果迭代器已将序列迭代完毕,则为true。这种情况下,value是可选的,如果它依然存在,即为迭代结束之后的默认返回值。
value
迭代器返回的任何JavaScript值。done为true时可省略。
const iterator = {//有nextnext:function (){//有返回值return {done:true,value:'aaa'}}
}
迭代器的代码练习:
// 数组
const array = ['abc', 'bcd', 'dba']// 创建一个迭代器来遍历数组
let index = 0
const namesIterator = {next() {if(index < array.length){return { done:false, value:array[index++] }}else{return{ done :true,value :undefined }}}
}
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())
结果:
可迭代对象
它和当前是不同的概念;
当一个对象实现了iterable protocol协议(可迭代协议)时,它就是一个可迭代对象;
这个对象的要求是必须实现 @@iterator方法,在代码中我们使用Symbol.iterator访问该属性;
那么可迭代对象有什么好处呢?
当一个对象变成一个可迭代对象时,进行某些迭代操作,比如for…of操作时,其实就会调用它的@@iterator方法
可迭代对象代码:
const iteratorObj = {names: ['abc', 'cef', 'fed'],[Symbol.iterator]() {let index = 0return {next:() => {if (index < this.names.length) {return { done: false, value: this.names[index++] }} else {return { done: true, value: undefined }}}}}
}
const iterator = iteratorObj[Symbol.iterator]()
console.log(iterator.next())
当我们用for…of方法去遍历上面这段代码时(可迭代对象)就会遍历出来
for(let iterators of iteratorObj) {console.log(iterators) //可以使用for ... of()
}
结果:
而我们对普通对象进行for…of遍历时是会报错的
// for...of
const obj = {name:'ljb',age:18
}// 这里的obj就不能使用for..of 因为它不是一个可迭代对象
for(let item of obj) {console.log(item) // 报错:TypeError: obj is not iterable (可迭代的)
}
原生迭代器对象
JS本身就有内置的迭代器对象:
String、Array、Map、Set、arguments对象,NodeList集合;
const names = ['abc', 'cdf', 'fgd'] //字面量for(let item of names ){console.log(item)
}
可迭代对象的应用
1.Javascript中语法:for … of 、展开语法(spread syntax) 、yield*、解构赋值(Destructuring_assignment);
2.创建一些对象时:new Map([Iterable])、new WeakMap([iterable])、new Set([iterable])、new WeakSet([iterable]);
3.一些方法的调用:Promise.all(iterable)、Promise.race(iterable)、Array.from(iterable);
const iteratorObj = {names: ['abc', 'dbc', 'def'],[Symbol.iterator]() {let index = 0return {next: () => {if (index < this.names.length) {return { done: false, value: this.names[index++] }} else {return { done: true, value: undefined }}}}}
}const arr = [10, 20, 30, 40, 40]
const newArr = [...arr,...iteratorObj]
自定义类的迭代
在上面Array,Set、String、Map等类创建出来的对象都是可迭代对象
在面向对象开发中,我们可以通过class定义一个自己的类,这个类可以创建很多的对象
如果我们也希望自己的类创建出来的对象默认是可迭代的,那么在设计类的时候我们可以添加上@@iterator方法;
class Classroom {constructor(adddress, name, students) {this.adddress = adddressthis.name = namethis.students = students}[Symbol.iterator](){let index = 0return {next:() =>{if(index<this.students.length){return { done :false,value:this.students[index++] }}else{return { done:true ,value:undefined }}}}}
}const classroom = new Classroom('重庆', '计算机教室', ['jack', 'Tom', 'curry'])for(let item of classroom) {console.log(item)
}
迭代器的中断
迭代器在某些情况下会在没有完全迭代的情况下中断:
比如遍历的过程中通过break、continue、return、throw中断了循环操作;
比如在解构的时候,没有解构所有的值;
这个时候我们想要监听中断的话,可以添加return方法:
[Symbol.iterator](){let index = 0return {next:() =>{if(index<this.students.length){return { done :false,value:this.students[index++] }}else{return { done:true ,value:undefined }}},//迭代器的中断return() {console.log('迭代器提前终止了')return { done :true }}}}
for(let item of classroom) {console.log(item)if(item === 'Tom') break
}
结果:
生成器
什么是生成器?
生成器是ES6中新增的一种函数控制,使用的方案,它可以让我们更加灵活的控制函数什么时候继续执行、暂停执行等。
生成器函数也是一个函数,但是和普通函数有一些区别:
首先,生成器函数需要在function的后面加一个符号:*
其次,生成器函数可以通过yield关键字来控制函数的执行流程:
最后,生成器函数的返回值是一个Generator(生成器):
- 生成器事实上是一种特殊的迭代器;
- MDN:Instead,they return a special type of iterator,called a Generator
生成器函数执行
我们如何让它执行函数中的东西呢?调用next即可;
迭代器的next是会有返回值的
但是我们很多时候不希望next返回的是一个undefined,这个时候我们就可以通过yield来返回结果:
function* foo() {const value1 = 10console.log(value1)yield value1const value2 = 20 console.log(value2)const value3 = 30 console.log(value3)yield value2console.log('函数执行结束~')
}
const genertor = foo()
console.log(genertor.next())
console.log(genertor.next())
结果:
生成器传递参数-next函数
函数既然可以暂停来分段执行,那么函数应该是可以传递参数的,我们是否可以给每个分段来传递参数呢?
那肯定是可以的;
我们在调用next函数的时候,可以给它传递参数,那么这个参数会作为上一个yield语句的返回值
注意:也就是说我们是为本次的函数代码块执行提供了一个值;
function* foo() {const value1 = 10console.log(value1)const n = yield value1const value2 = 20 + nconsole.log(value2)yield value2 const value3 = 30 console.log(value3)yield value3console.log('函数执行结束~')
}
const genertor = foo() console.log(genertor.next())console.log(genertor.next(100))
console.log(genertor.next())
console.log(genertor.next())
生成器提前结束-return函数
还有一个可以给生成器函数传递参数的方法就是提供return函数;
return函数传值后这个生成器函数就会结束,之后调用next不会继续生成值了;
function* foo() {const value1 = yield 'aaa'console.log('value1:',value1)const value2 = yield value1const value3 = yield value1
}
const generator = foo()
console.log(generator.next())
console.log(generator.return(123))
console.log(generator.next())
生成器替代迭代器
我们发现生成器是一种特殊的迭代器,那么在某些情况下我们可以使用生成器来代替迭代器:
// 生成器代替迭代器
function* createArrayIterator(arr) {for(let item of arr) {yield item}}
const names = ['abc', 'dbc', 'cdf']
const namesIterator = createArrayIterator(names)
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())
console.log(namesIterator.next())
事实上我们还可以使用yield* 来生产一个可迭代对象:
这个时候相当于是一种yield的语法糖,只不过会依次迭代这个可迭代对象,每次迭代其中的一个值
JavaScript的迭代器与生成器相关推荐
- JavaScript之迭代器and生成器
JS高级学习笔记(下) 迭代器(iterator) 可迭代对象 可迭代对象的应用 生成器 生成器传递参数--next函数 生成器替代迭代器 异步函数(async function) await 关键字 ...
- javascript迭代器_JavaScript符号,迭代器,生成器,异步/等待和异步迭代器-全部简单解释...
javascript迭代器 by rajaraodv 通过rajaraodv JavaScript符号,迭代器,生成器,异步/等待和异步迭代器-全部简单解释 (JavaScript Symbols, ...
- 掌握JavaScript中的迭代器和生成器,顺便了解一下async、await的原理
掌握JavaScript中的迭代器和生成器,顺便了解一下async.await的原理 目录 掌握JavaScript中的迭代器和生成器,顺便了解一下async.await的原理 前言 1.迭代器(It ...
- [ES6] 细化ES6之 -- 迭代器与生成器
Symbol Symbol是什么 ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值 Symbol 值通过Symbol函数生成 let symbol = Symbol(); consol ...
- ES6 迭代器与生成器(非常详细、容易理解)
下面是对ES6中迭代器和生成器的整理,非常详细.容易理解,希望可以帮助到有需要的小伙伴~ 文章目录 迭代器是什么 Iterator接口 迭代协议 for...of语句的用法 返回迭代器对象的方法 与f ...
- 完全理解Python迭代对象、迭代器、生成器
本文源自RQ作者的一篇博文,原文是Iterables vs. Iterators vs. Generators,俺写的这篇文章是按照自己的理解做的参考翻译,算不上是原文的中译版本,推荐阅读原文,谢谢网 ...
- Python学习笔记3 流程控制、迭代器、生成器
第3章 流程控制.迭代器.生成器 3.1 选择语句 1.语法:(1)if -else (2)if-elif-else 2.注意:(1)每个条件后面要使用冒号:(2)使用缩进划分语句块(3)python ...
- pythonfor循环遍历list_为什么for循环可以遍历list:Python中迭代器与生成器
1 引言 只要你学了Python语言,就不会不知道for循环,也肯定用for循环来遍历一个列表(list),那为什么for循环可以遍历list,而不能遍历int类型对象呢?怎么让一个自定义的对象可遍历 ...
- 完全理解 Python 迭代对象、迭代器、生成器(转)
完全理解 Python 迭代对象.迭代器.生成器 本文源自RQ作者的一篇博文,原文是Iterables vs. Iterators vs. Generators » nvie.com,俺写的这篇文章是 ...
最新文章
- java经典模式:七种模式样例
- DNS隧道工具汇总——补充,还有IP over DNS的工具NSTX、Iodine、DNSCat
- python语法总结-Python and、or以及and-or语法总结
- SQL数据库权限授予grant
- 嵌入式Linux操作UART实例
- 如何抓取一个网站的分页_如何设计一个吸引人的网站
- 转贴:Icon Design Guidelines, Android 2.0
- 测试用什么编译java代码_java – 测试编译器
- 在Eclipse中实现C++ 11的完整支持
- 【SNMP】snmp trap 介绍、安装、命令|Trap的发送与接收代码实现
- 【面向校招】Golang面试题总结
- 基于多源传感器融合的导航定位综述方法分析
- 十大IT危机处理高手
- matlab特征值意义,特征值
- MATLAB Simulink
- MathWorks 中国
- python幸运七实验_【python爬虫】原神公测预抽卡活动自动化抽卡脚本
- Windows安全加固简介
- 三代测序数据自纠错技术 和 二代测序数据对三代测序数据纠错的技术。
- 架构系列---一套高并发IM通信系统完整设计和实现
- html3D效果可以在手机打开吗,HTML手机怎么打开
- Android逆向工程-破解 哈皮妹-萝莉
热门文章
- 2019法定节假日sql文件
- 汕头大学计算机英语复试,汕头大学计算机系2021年硕士研究生复试办法
- 数字IC设计 - 数字IC实现途径
- 自动驾驶2021·谁将引领下一个10年?
- 手把手教怎么制作U盘启动系统盘,Ventoy工具下载和使用
- C++实现求小于n的所有素数
- 超分辨率图像重建算法综述
- studio和solo哪个好_图文评测曝光beatsstudio3和solo3哪个好?区别如何?真相吐槽内情...
- phpcms调用广告(ad)列表方法封装
- 年会弹幕文字_企业年会节目(精华版)