迭代器与生成器

  • 迭代器
    • 什么是迭代器?
    • 可迭代对象
    • 原生迭代器对象
    • 可迭代对象的应用
    • 自定义类的迭代
  • 生成器
    • 什么是生成器?
    • 生成器传递参数-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的迭代器与生成器相关推荐

  1. JavaScript之迭代器and生成器

    JS高级学习笔记(下) 迭代器(iterator) 可迭代对象 可迭代对象的应用 生成器 生成器传递参数--next函数 生成器替代迭代器 异步函数(async function) await 关键字 ...

  2. javascript迭代器_JavaScript符号,迭代器,生成器,异步/等待和异步迭代器-全部简单解释...

    javascript迭代器 by rajaraodv 通过rajaraodv JavaScript符号,迭代器,生成器,异步/等待和异步迭代器-全部简单解释 (JavaScript Symbols, ...

  3. 掌握JavaScript中的迭代器和生成器,顺便了解一下async、await的原理

    掌握JavaScript中的迭代器和生成器,顺便了解一下async.await的原理 目录 掌握JavaScript中的迭代器和生成器,顺便了解一下async.await的原理 前言 1.迭代器(It ...

  4. [ES6] 细化ES6之 -- 迭代器与生成器

    Symbol Symbol是什么 ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值 Symbol 值通过Symbol函数生成 let symbol = Symbol(); consol ...

  5. ES6 迭代器与生成器(非常详细、容易理解)

    下面是对ES6中迭代器和生成器的整理,非常详细.容易理解,希望可以帮助到有需要的小伙伴~ 文章目录 迭代器是什么 Iterator接口 迭代协议 for...of语句的用法 返回迭代器对象的方法 与f ...

  6. 完全理解Python迭代对象、迭代器、生成器

    本文源自RQ作者的一篇博文,原文是Iterables vs. Iterators vs. Generators,俺写的这篇文章是按照自己的理解做的参考翻译,算不上是原文的中译版本,推荐阅读原文,谢谢网 ...

  7. Python学习笔记3 流程控制、迭代器、生成器

    第3章 流程控制.迭代器.生成器 3.1 选择语句 1.语法:(1)if -else (2)if-elif-else 2.注意:(1)每个条件后面要使用冒号:(2)使用缩进划分语句块(3)python ...

  8. pythonfor循环遍历list_为什么for循环可以遍历list:Python中迭代器与生成器

    1 引言 只要你学了Python语言,就不会不知道for循环,也肯定用for循环来遍历一个列表(list),那为什么for循环可以遍历list,而不能遍历int类型对象呢?怎么让一个自定义的对象可遍历 ...

  9. 完全理解 Python 迭代对象、迭代器、生成器(转)

    完全理解 Python 迭代对象.迭代器.生成器 本文源自RQ作者的一篇博文,原文是Iterables vs. Iterators vs. Generators » nvie.com,俺写的这篇文章是 ...

最新文章

  1. java经典模式:七种模式样例
  2. DNS隧道工具汇总——补充,还有IP over DNS的工具NSTX、Iodine、DNSCat
  3. python语法总结-Python and、or以及and-or语法总结
  4. SQL数据库权限授予grant
  5. 嵌入式Linux操作UART实例
  6. 如何抓取一个网站的分页_如何设计一个吸引人的网站
  7. 转贴:Icon Design Guidelines, Android 2.0
  8. 测试用什么编译java代码_java – 测试编译器
  9. 在Eclipse中实现C++ 11的完整支持
  10. 【SNMP】snmp trap 介绍、安装、命令|Trap的发送与接收代码实现
  11. 【面向校招】Golang面试题总结
  12. 基于多源传感器融合的导航定位综述方法分析
  13. 十大IT危机处理高手
  14. matlab特征值意义,特征值 - MATLAB Simulink - MathWorks 中国
  15. python幸运七实验_【python爬虫】原神公测预抽卡活动自动化抽卡脚本
  16. Windows安全加固简介
  17. 三代测序数据自纠错技术 和 二代测序数据对三代测序数据纠错的技术。
  18. 架构系列---一套高并发IM通信系统完整设计和实现
  19. html3D效果可以在手机打开吗,HTML手机怎么打开
  20. Android逆向工程-破解 哈皮妹-萝莉

热门文章

  1. 2019法定节假日sql文件
  2. 汕头大学计算机英语复试,汕头大学计算机系2021年硕士研究生复试办法
  3. 数字IC设计 - 数字IC实现途径
  4. 自动驾驶2021·谁将引领下一个10年?
  5. 手把手教怎么制作U盘启动系统盘,Ventoy工具下载和使用
  6. C++实现求小于n的所有素数
  7. 超分辨率图像重建算法综述
  8. studio和solo哪个好_图文评测曝光beatsstudio3和solo3哪个好?区别如何?真相吐槽内情...
  9. phpcms调用广告(ad)列表方法封装
  10. 年会弹幕文字_企业年会节目(精华版)