迭代器
迭代器是一个对象,让我们能够遍历某个数据结构(如:链表或数组)
在JS中,迭代器是一个对象且还需要有next函数(符合迭代器协议)
const iterator = {next: function() {return {}}}
next函数
一个 无参数函数,返回一个应当拥有done和value属性的对象:
done (boolean):
- 如果迭代器可以产生序列中的下一个值,则为 false。(这等价于没有指定 done 这个属性。)
- 如果迭代器已将序列迭代完毕,则为 true。这种情况下,value 是可选的,如果它依然存在,即为迭代结束之后的默认返回值。
value:迭代器返回的任何 JavaScript 值。done 为 true 时可省略。
// 数组
const names = ["abc", "cba", "nba"]
// 创建一个迭代器对象来访问数组
let index = 0
const namesIterator = {
next: function() {
if (index < names.length) {
return { done: false, value: names[index++] }
} else {
return { done: true, value: undefined }
}
}
}
console.log(namesIterator.next())
console.log(namesIterator.next())
可迭代对象
可迭代对象是一个对象且需要实现 @@iterator方法,我们可以使用Symbol.iterator访问该属性(符合可迭代协议)
const iterableObj = {[Symbol.iterator]: function(){return 迭代器}}
const iterableObj = {
names: ["abc", "cba", "nba"],
[Symbol.iterator]: function() {
let index = 0
return {
next: () => { // 使用箭头函数使this指向iterableObj
if (index < this.names.length) {
return { done: false, value: this.names[index++] }
} else {
return { done: true, value: undefined }
}
}
}
}
}
用于可迭代对象的语法:
- for ...of 可以遍历的东西必须是一个可迭代对象
- 展开运算符 (...) [ 在ES9之后新增的特性:普通对象也可以使用展开运算符 ]
- 解构赋值 [ 在ES9之后新增的特性:普通对象也可以使用解构赋值]
- yield*
- 使用Set 、Array.from 创建对象时需要传入可迭代对象
内置可迭代对象
String、Array、TypedArray、Map 和 Set 都是内置可迭代对象,因为它们的原型对象都拥有一个 Symbol.iterator 方法
// 以数组为例:
const names = ["abc", "cba", "nba"]
console.log(names[Symbol.iterator])
生成器
与函数相关,是ES6新增的一种函数控制、使用的方案(控制函数什么时候继续执行、暂停执行等操作)
生成器函数返回值是一个生成器
生成器函数
生成器函数特点:
- 生成器函数需要在function的后面加一个符号:*
- 生成器函数可以通过yield关键字来控制函数的执行流程
- 生成器函数的返回值是一个Generator(生成器)
function* foo() {
console.log("函数开始执行~")
const value1 = 100
console.log("第一段代码:", value1)
yield
const value2 = 200
console.log("第二段代码:", value2)
yield
console.log("函数执行结束~")
}
// 调用生成器函数时, 会给我们返回一个生成器对象
const generator = foo()
// 开始执行第一段代码
generator.next()
我们使用第一个next()调用的时候,执行的是第一个yield上面的代码
- 当遇到yield时候值暂停函数的执行
- 当遇到return时候生成器就停止执行
- 如果想要第一个next返回的结果不是undefined,则在yield之后加上想要返回的值:
yield value1
生成器本质上是一个特殊的迭代器
//打印的结果与迭代器的形式是一样的
const generator = foo()
console.log("返回值:", generator.next())
// 返回值: { value: undefined, done: false }
生成器的方法使用
next传递参数
我们在调用next函数的时候,可以给它传递参数,那么这个参数会作为上一个yield语句的返回值;而这个传递进来的参数则为下一个代码块执行提供了一个值
function* foo(num) {
console.log("函数开始执行~")
const value1 = 100 * num
console.log("第一段代码:", value1)
const n = yield value1
const value2 = 200 * n
console.log("第二段代码:", value2)
console.log("函数执行结束~")
return "123"
}
// 生成器上的next方法可以传递参数
//给第一个代码块传参
const generator = foo(5) // 传入的5被上面的num接收
generator.next()
// 给第二个代码块传参,传入的10对应上面的n
generator.next(10)
return终止执行
// 相当于在代码块的后面加上return, 就会提前终端生成器函数代码继续执行
generator.return(15)
用生成器替代迭代器
// 原先用迭代器实现:
function createArrayIterator(arr) {
let index = 0
return {
next: () => {
if (index < arr.length) {
return { done: false, value: arr[index++] }
} else {
return { done: true, value: undefined }
}
}
}
}
因为生成器是特殊的迭代器,所以我们可以用生成器去简化代码:
function* createArrayIterator(arr) {
for (const item of arr) {
yield item
}
}
yield*
yield*是一种yield的语法糖,可以用它来生产一个可迭代对象
如下面的 yield* arr ,这个代码会依次迭代 arr 这个可迭代对象,每次迭代其中的一个值
function* createArrayIterator(arr) {
yield* arr
}