Open yuqingc opened 4 years ago
迭代器和生成器
迭代器模式描述了,一个实现了 Iterable 接口的可迭代数据结构,该数据结构被 Iterator 所消费(consume),用以遍历。
Iterable
Iterator
Iterable 接口:必须含有一个名为 [Symbol.iterator] 的属性,其值是一个 iterator 工厂函数,调用时返回一个新的迭代器
[Symbol.iterator]
实现 Iterable 的一些内置对象
String
Array
Map
Set
arguments 对象
一些 DOM 相关的对象,比如 NodeList
NodeList
一些会语法需要传入(接受) Iterable 对象,这些语法会隐式调用 iterator 工厂方法
for...of
数组解构
... 数组展开操作符
...
Array.from()
Set 和 Map 的构造函数
Promise.all(), Promise.race()
Promise.all()
Promise.race()
生成器内的 yield* 操作符
yield*
包含一个 next() 方法用来遍历 Iterable 对象的值
next()
next() 方法返回一个 IteratorResult 对象,包含下一次的值:
IteratorResult
含有属性 value,当前的值
value
含有属性 done,一个 boolean 值,表示是否已经迭代结束
done
只有调用 next() 方法才能获取当前迭代器的位置
当迭代器到达 done: true,则调用 next() 会变成幂等(调用 n 次的结果和影响是一样的)操作
done: true
每一个通过工厂方法生成的 iterator 的遍历是互相独立的
迭代器会保存 Iterable 对象的索引,因此会阻止 GC
每个 iterable 对象也是一个 Iterable,其 Symbol.iterator 属性指向一个返回他本身的一个工厂方法
Symbol.iterator
迭代器有一个可选的 return() 方法,用来终止迭代器。该方法返回一个 IteratorResult 对象
return()
因为 return() 方法是可选的,JS 的数组对象没有该方法,因此会出现下面的结果
let arr = [3, 1, 4]; let iter = arr[Symbol.iterator](); for (let item of arr) { console.log(item); } // 3 // 1 // 4 for (let item of iter) { console.log(item); } // 3 // 1 // 4
注意:箭头函数不能用来定义 Generator
Generator 函数定义
function* foo () {} let foo = function* () {} let ojb = { * foo () {} } class Obj { * foo () {} } class Obj { static * foo () {} }
Generator 函数调用会返回一个 Generator 对象,该对象可以理解为一个状态机,刚开始处于一个 suspended 状态
suspended
每一个 Generator 对象都实现了 Iterator 接口,内部含有 next() 方法和 return() 方法
每一个Generator 对象也实现了 Iterable 接口,其工厂函数 Symbol.iterator 返回本身
yield
每次调用 Generator 函数会返回一个新的 Generator 对象,他们的迭代调用过程互相独立,互不影响
可以结合 yield 把 Generator 对象当作迭代器使用
function* counter (n) { while(n--) { yield n; } } for (const item of counter(10)) { console.log(item); } // 10 // 9 // 8 // 7 // ... // 1 // 0
第一次调用的 next() 不需要传入参数,遇到 第一个 yield 停下
遇到 yield x 停下,并且把 x 作为 next() 的返回的 IteratorResult 对象中的 value 属性
yield x
x
再次调用 next(y) 会做两件事
next(y)
先把 y 的值传给当前的 yield
y
越过当前的 yield 继续执行,直到遇到下一个 yield z
yield z
把 x 放如当前 next 的返回值的 value 属性
next
接受下次调用的 next() 的参数并传给 yield
let result = yield* [1, 2, 3]; // result 的值是 undefined // 相当于 // yield 1; // yield 2; // yield 3;
undefined
return() 方法,使状态由 suspended 转移为 closed。
closed
返回一个 IteratorResult
返回值的 value 属性就是传入 return() 的参数
throw() 方法
throw()
抛出传入的错误,并 close Generator
如果在 Generator 内部 catch 了 yield 表达式,则某次 throw 会跳过这次 yield,并继续往下执行
07 Iterator & Generator
迭代器和生成器
迭代器
迭代器背景
迭代器模式
迭代器模式描述了,一个实现了
Iterable
接口的可迭代数据结构,该数据结构被Iterator
所消费(consume),用以遍历。Iterable 对象接口
Iterable 接口:必须含有一个名为
[Symbol.iterator]
的属性,其值是一个 iterator 工厂函数,调用时返回一个新的迭代器实现
Iterable
的一些内置对象String
Array
Map
Set
arguments 对象
一些 DOM 相关的对象,比如
NodeList
一些会语法需要传入(接受) Iterable 对象,这些语法会隐式调用 iterator 工厂方法
for...of
数组解构
...
数组展开操作符Array.from()
Set 和 Map 的构造函数
Promise.all()
,Promise.race()
生成器内的
yield*
操作符Iterator 对象接口
包含一个
next()
方法用来遍历 Iterable 对象的值next()
方法返回一个IteratorResult
对象,包含下一次的值:含有属性
value
,当前的值含有属性
done
,一个 boolean 值,表示是否已经迭代结束只有调用
next()
方法才能获取当前迭代器的位置当迭代器到达
done: true
,则调用next()
会变成幂等(调用 n 次的结果和影响是一样的)操作每一个通过工厂方法生成的 iterator 的遍历是互相独立的
迭代器会保存 Iterable 对象的索引,因此会阻止 GC
每个 iterable 对象也是一个 Iterable,其
Symbol.iterator
属性指向一个返回他本身的一个工厂方法迭代器的终止
迭代器有一个可选的
return()
方法,用来终止迭代器。该方法返回一个IteratorResult
对象因为
return()
方法是可选的,JS 的数组对象没有该方法,因此会出现下面的结果Generator
基础语法
Generator 函数定义
Generator 函数调用会返回一个 Generator 对象,该对象可以理解为一个状态机,刚开始处于一个
suspended
状态每一个 Generator 对象都实现了 Iterator 接口,内部含有
next()
方法和return()
方法next()
方法可以获取函数内部定义的返回值每一个Generator 对象也实现了 Iterable 接口,其工厂函数
Symbol.iterator
返回本身yield
用来中断函数的执行每次调用 Generator 函数会返回一个新的 Generator 对象,他们的迭代调用过程互相独立,互不影响
可以结合
yield
把 Generator 对象当作迭代器使用使用
yield
传入/传出 值第一次调用的
next()
不需要传入参数,遇到 第一个yield
停下遇到
yield x
停下,并且把x
作为next()
的返回的IteratorResult
对象中的value
属性再次调用
next(y)
会做两件事先把
y
的值传给当前的yield
越过当前的
yield
继续执行,直到遇到下一个yield z
总结一下遇到
yield x
会发生什么把
x
放如当前next
的返回值的value
属性接受下次调用的
next()
的参数并传给yield
yield*
可以解构一个 Iterablenext()
中读取值,因此 yield 的返回值是undefined
Generator 的提前终止
return()
方法,使状态由suspended
转移为closed
。返回一个
IteratorResult
返回值的
value
属性就是传入return()
的参数throw()
方法抛出传入的错误,并 close Generator
如果在 Generator 内部 catch 了 yield 表达式,则某次 throw 会跳过这次 yield,并继续往下执行