迭代器与生成器

1.迭代

反复多次执行一段程序,(有明确的终止条件)

迭代器、生成器 ES6

  • 计数循环(for):最简单的迭代

    迭代次数、迭代每次执行的操作 (顺序已知)

  • 古早迭代(有序->数组):①必须数组,需引用数组本身;②递增索引的方式

  • 通用迭代(ES5):forEach

    • 优点:不需引用数组自身;不需索引
    • 缺点:只限数组直接调用,不能手动终止

2. 迭代器模式

内置可迭代类型:

String、Array、Map、Set、arguments对象、NodeList等DOM集合类型

  1. (迭代的自我识别)有默认迭代器属性,键为Symbol.iterator,值为迭代器工厂函数

  2. (创建Iterator对象的能力)迭代器工厂函数返回【实现Iterator接口的对象】

    即包含键为next的属性、可能也包含键为return的属性

自动调用默认迭代器工厂函数来生成迭代器的操作:

for-of、数组解构、扩展操作符

Array.from(...)、new Set(...)、new Map(...)

Promise.all(...)、Promise.race(...)

yield* ...

Iterator维护一个指向可迭代对象的引用,会阻止垃圾回收。

每个内置可迭代对象的默认迭代器函数所产生的迭代器,也有自己的默认迭代器函数,返回指向自身(并未严格实现Iterable接口,默认迭代器函数不能创建新的迭代器)

class Counter {
constructor(limit) {
this.limit = limit;
} [Symbol.iterator]() {
let count = 1,
o = this; return {
next() {
if( count <= o.limit) {
return {
done: false,
value: count++
};
} else {
return {
done: true
};
}
},
return() {
console.log( 'Exiting early' );
return {
done: true
};
}
}
}
} let counter1 = new Counter(5);
for (let i of counter1) {
if(i > 2) {
break;
}
console.log( i );
}
// 1
// 2
// Exiting early
let counter3 = new Counter(5);
let [a, b] = counter3;
console.log( a );
console.log( b );
// Exiting early
// 1
// 2 console.log( "//======= 数组的迭代器不能关闭" );
let a1 = [1, 2, 3, 4, 5];
let iter = a1[Symbol.iterator]();
for (let i of iter) {
console.log( i );
if(i > 2) {
break;
}
}
for (let i of iter) {
console.log( i );
}
// 1
// 2
// 3
// 4
// 5

3. 生成器 generator

函数加前缀*号(箭头函数不行)——>生成器函数

/*
Function generator() {
constructor() {
this = {
next() {
// ...
}
}
return this;
}
[Symbol.iterator]() {
return this;
}
}
*/
let g = generator();
g === g[Symbol.iterator]

使用场景(yield):

  1. 生成器对象作为可迭代对象(有默认[Symbol.iterator]为键的属性,无实现创建新迭代器的工厂函数)

  2. yield实现输入输出

    给next方法传参,参数会被当作上一个yield操作的结果值

  3. 产生可迭代对象

    yield* 可迭代对象

    yield*操作的结果值为 Iterable对象遍历到done为true时的value属性的值

  4. 实现递归 yield*(function* + yield*)

    可将递归结果包装成一个生成器对象(实现Iterator接口)

其他:

  • 生成器函数可以作为默认迭代器(工厂函数)

    产生->生成器对象(实现Iterator接口)

  • 生成器对象有API throw()

    生成器函数内部处理,可继续——>跳过当下的yield操作(去到下一个yield);没处理,就迭代终止。

function *generatorFn() {
return 'foo';
}
let generatorObject = generatorFn();
console.log( generatorObject );
console.log( generatorObject.next() );
// Object [Generator] {} generatorFn {<suspended>}
// { value: 'foo', done: true } {value: "foo", done: true}
function *generatorFn2() {
console.log( 'foobar' );
}
generatorObject = generatorFn2();
generatorObject.next(); // foobar
generatorObject.next(); function* generatorFn3() {
yield 'foo';
yield 'bar';
return 'baz';
}
let g3 = generatorFn3();
console.log( g3.next() );
console.log( g3.next() );
console.log( g3.next() );
// { value: 'foo', done: false }
// { value: 'bar', done: false }
// { value: 'baz', done: true }
g3 = generatorFn3();
for(const x of g3) {
console.log( x );
}
// foo
// bar
g3 = generatorFn2();
for(const x of g3) {
console.log( x );
}
// foobar
class Node {
constructor(id) {
this.id = id;
this.neighbors = new Set();
} connect(node) {
if (node !== this) {
this.neighbors.add( node );
node.neighbors.add( this );
}
}
} class RandomGraph {
constructor(size) {
this.nodes = new Set(); for (let i = 0; i< size; ++ i) {
this.nodes.add( new Node(i) );
} const threshold = 1 / size;
for (const x of this.nodes) {
for (const y of this.nodes) {
if (Math.random() < threshold) {
x.connect( y );
}
}
}
} print() {
for (const node of this.nodes) {
const ids = [...node.neighbors].map(n => n.id).join(','); console.log( `${node.id}: ${ids}` );
}
} // 整张图是否连通
isConnected() {
const visitedNodes = new Set(); function *traverse(nodes) {
for (const node of nodes) {
if (!visitedNodes.has(node)) {
yield node;
yield* traverse(node.neighbors);
}
}
}
// 取得集合中的第一个节点
const firstNode = this.nodes[Symbol.iterator]().next().value;
// 使用递归生成器迭代每个节点
for (const node of traverse([firstNode])) {
visitedNodes.add(node);
}
// function traverse(nodes) {
// for (const node of nodes) {
// if (!visitedNodes.has(node)) {
// visitedNodes.add(node);
// traverse(node.neighbors);
// }
// }
// } return visitedNodes.size === this.nodes.size;
}
} const g = new RandomGraph(6);
g.print();
// 0: 1,2
// 1: 0,5
// 2: 0
// 3:
// 4: 5
// 5: 1,4
console.log( g.isConnected() ); console.log( '实现输入输出1===========' )
function *generatorFn(initial) {
// console.log( initial );
console.log( yield 1 );
console.log( yield 2 );
return yield 3;
}
let genObj = generatorFn('foo');
console.log( genObj.next('bar') );
console.log( genObj.next('baz') );
console.log( genObj.next('qux') );
console.log( genObj.next() );
// { value: 1, done: false }
// baz
// { value: 2, done: false }
// qux
// { value: 3, done: false }
// { value: undefined, done: true } console.log( '实现输入输出2===========' )
function *generatorFn2() {
return yield 'foo';
}
let genObj2 = generatorFn2();
console.log( genObj2.next() );
console.log( genObj2.next('bar') );
console.log( genObj2.next('test') );
// { value: 'foo', done: false }
// { value: 'bar', done: true } // 相当于给done的时候的value赋值?
// { value: undefined, done: true }
for (const x of generatorFn2()) {
console.log( x );
}
// foo function* zeroes(n) {
while(n--) {
yield 0;
}
}
console.log( Array.from(zeroes(8)) ); function *innerGeneratorFn() {
yield 'foo';
return 'bar';
}
function *outerGeneratorFn() {
console.log('iter value: ', yield* innerGeneratorFn());
}
for(const x of outerGeneratorFn()) {
console.log( 'value: ', x );
}
// value: foo
// iter value: bar
for(const x of innerGeneratorFn()) {
console.log( x );
}
// foo class Foo {
constructor() {
this.values = [1, 2, 3];
}
* [Symbol.iterator]() {
yield* this.values;
}
// [Symbol.iterator]() {
// let i = 0, len = this.values.length, o = this;
// return {
// next() {
// return {
// value: o.values[i++],
// done: i > len
// }
// }
// }
// }
}
const f = new Foo();
for(const x of f) {
console.log( x );
}
// 1
// 2
// 3

JavaScript高级程序设计笔记07 迭代器与生成器的更多相关文章

  1. JavaScript高级程序设计笔记之面向对象

    说起面向对象,大部分程序员首先会想到 类 .通过类可以创建许多具有共同属性以及方法的实例或者说对象.但是JavaScript并没有类的概念,而且在JavaScript中几乎一切皆对象,问题来了,Jav ...

  2. javascript高级程序设计--笔记01

    概述 JavaScript的实现包含三个部分: 1  核心(ECMAScript)   提供核心语言功能 2  文档对象模型(DOM)  一套提供了访问以及操作网页内容的API 3  浏览器对象模型( ...

  3. javascript事件小结(事件处理程序方式)--javascript高级程序设计笔记

    1.事件流:描述的是从页面中接收事件的顺序. 2.事件冒泡:IE的事件流叫做事件冒泡,即事件开始从具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到不具体的节点(文档). 3.事件捕获 ...

  4. JavaScript高级程序设计笔记(一)

    ---恢复内容开始--- 前三章为基础知识,为了方便以后查看,所以比较啰嗦.这里对函数的基本操作没有记录. 1.JavaScript的实现 虽然 JavaScript 和 ECMAScript 通常都 ...

  5. JavaScript高级程序设计笔记 事件冒泡和事件捕获

    1.事件冒泡 要理解事件冒泡,就得先知道事件流.事件流描述的是从页面接收事件的顺序,比如如下的代码: <body> <div> click me! </div> & ...

  6. <javascript高级程序设计>笔记

    1.要讲一个值转换成其对应的Boolean类型 ,可以调用转型函数Boolean(). var message=“hello world!”; var messageAsBoolean=Boolean ...

  7. javaScript高级程序设计笔记 2

    Undefinde Null Boolean Number String    基本类型 Object    引用类型 只有引用类型才能动态的添加属性 赋值基本类型和引用类型也不相同,复制的基本类型的 ...

  8. javaScript高级程序设计笔记 1

    核心  ECMAScript 文档对象模型  DOM 浏览器对象模型 BOM 延迟脚本  defer typeof操作符      判断字符类型  返回   undefined  boolean  s ...

  9. Javascript高级程序设计笔记 <第五章> 引用类型

    一.object类型 创建object实例的方式有两种: //第一种使用new操作符跟构造函数 var person= new Object(); person.name="小王" ...

  10. Javascript高级程序设计笔记(很重要尤其是对象的设计模式与继承)

    var obj = {'a':'a'}; var fun = function (){} console.log(typeof obj);//object console.log(typeof fun ...

随机推荐

  1. [爬虫]1.2.2 CSS选择器

    CSS (Cascading Style Sheets) 是一种样式表语言,用于描述HTML元素的样式.CSS选择器是CSS规则的一部分,它决定了CSS规则应用于哪些元素.在网络爬虫的开发中,我们经常 ...

  2. 使用调试工具调试博图TCP连接所遇到的问题

    PLC端使用的指令 PLC为服务器端,电脑为客户端,以上为服务器与客户端的配置参数 启动连接后连接成功,PLC的IP地址也可以ping通 ------------------------------- ...

  3. 2023-7-27 WPF自定义命名空间在xaml中的使用

    xaml自定义命名空间 [作者]长生 为啥要用自定义命名空间 这是常见的几种命名空间 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/ ...

  4. Axios向后段请求数据GET POST两种方法的不同之处

    GET请求 向后端请求时,通过URL向后端传递参数 axios({ url:'http://127.0.0.1:9000/get-user-list/', type:'json', //GET方法携带 ...

  5. Oracle 11g手工建库

    搭建环境 1.建立相应的目录 mkdir /u01/app/oracle/oradata/test1 mkdir /u01/app/oracle/fast_recovery_area/test1 mk ...

  6. 【.NET6 + Vue3 + CentOS7.9 + Docker + Docker-Compose + SSL】个人博客前后端运维部署

    个人博客 前端:https://lujiesheng.cn 个人博客 后端:https://api.lujiesheng.cn 个人博客 运维:https://portainer.lujiesheng ...

  7. centos7安装weblogic

    前言 简介:weblogic是java应用服务器软件的一种,类似于tomcat,但功能更多,适用于大型应用场景. 版本: 系统:centos 7(最小化安装,无图形化界面) jdk: oraclejd ...

  8. [docker]安装常见数据库

    前言 本文使用docker安装常见数据库大部分没配置什么参数,只是基本的安装. 不只是数据库,还有elasticsearch.rabbitmq等和数据相关的服务. docker 版本: 18.06.3 ...

  9. java file I/O流

    一.File的简介:(java.io包) 生活中的文件: (1)文件的作用:持久化(瞬时状态的对立面状态) (1)文件的定义:一堆数据的集合 (2)文件存储的位置:磁盘,硬盘,软盘,U盘等等 计算机中 ...

  10. maven系列:基本命令(创建类、构建打包类、IDEA中操作)

    目录 一.创建类命令 创建普通Maven项目 创建Web Maven项目 发布第三方Jar到本地库中 二.构建打包类命令 编译源代码 编译测试代码 编译测试代码 打包项目 清除打包的项目 清除历史打包 ...