1. 迭代器
1.1 迭代器对象
迭代器(iterator)使用户在容器对象(container,例如链表或者数组)上遍访的对象,使用该接口无须关心对象的内部实现细节。
在 JavaScript 中,迭代器也是一个具体的对象,这个对象需要符合迭代器协议(iterator protocol):
- 迭代器协议中
产生了一系列值(无论是有限还是无限个)的标准方式; - 在 JavaScript 中这个标准就是一个
特定的 next 方法
next 方法有如下的要求:
- 一个
无参数或者一个参数的函数,返回一个应当拥有以下两个属性的对象: done(Boolen)- 如果迭代器可以产生序列中的下一个值,则为 false
- 如果迭代器已将序列迭代完毕,则为 true。在这种情况下,value 值是可选的,如果它依然存在,则为迭代结束之后的默认值。
- value
- 迭代器返回的任何 JavaScript 值。done 为 true 时可省略。
示例:实现一个数组的迭代器方法
const names = ["abc", "cba", "nba"]
const nums = [1, 2, 3, 4, 5]
function createArrayIterator(arr) {
let index = 0
return {
next: function() {
if (index < arr.length) {
return { done: false, value: arr[index++] }
} else {
return { done: true }
}
}
}
}
const namesIterator = createArrayIterator(names)
const numsIterator = createArrayIterator(nums)
namesIterator.next()
numsIterator.next()
1.2 可迭代对象
- 将一个普通的对象变成一个可迭代对象
- 必须实现一个特定的函数: [Symbol.iterator]
- 这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)
const infos = {
// 遍历数组
friends: ["rachel", "ross", "monica", "chandler", "phobes", "joey"]
[Symbol.iterator]: function() {
let index = 0
const infosIterator = {
next: () => {
if (index < this.friends.length) {
return { done: false, value: this.friends[index++] }
} else {
return { done: true }
}
}
}
return infosIterator
}
// 遍历普通键值对
name: 'fog',
age: 18,
[Symbol.iterator]: function() {
const keys = Object.key(this)
// const values = Object.values(this)
// const entries = Object.entries(this)
let index = 0
const iterator = {
next: () => {
if (index < keys.length) {
return { done: false, value: keys[index++] }
} else {
return { done: true }
}
}
}
return iterator
}
}
- 可以使用 for of 操作
for (const item of infos) {
console.log(item)
}
-
数组是一个可迭代对象 数组内部默认已经实现了 [Symbol.iterator] 函数
const friendsIterator = freinds[Symbol.iterator]()
-
可迭代对象的应用
- JavaScript 中的语法:for...of、展开语法、yield* iterable、解构赋值
- 创建对象:new Map(iterable)、new WeakMap(iteralbe)、new Set(iteralbe)、new WeakSet(iteralbe)
- 一些方法的调用:Promise.all(iteralbe)、Promise.race(iteralbe)、Array.from(iteralbe)
1.3 迭代器的中断
迭代器在某些情况下会在没有完全迭代的情况下中断:
- 比如遍历的过程汇总通过
break、return、throw 中断了循环操作 - 在解构的时候,没有解构所有的值
具体实现:
[Symbol.iterator]() {
return: () => {
console.log('iterator break')
return { done: true }
}
}
2. 生成器
2.1 定义
生成器是 ES6 中新增的一种函数控制、使用的方案,、它可以让我们更加灵活的控制函数什么时候继续执行、暂停执行。
2.2 生成器函数
生成器函数需要在 function 的后面加上一个符号:*生成器函数可以通过 yield 关键字来控制函数的执行那个流程生成器函数的返回值是一个 Generator(生成器)生成器实际上是一种特殊的迭代器
// 普通方式
function* foo() {
console.log('1111')
console.log('2222')
yield
console.log('3333')
console.log('4444')
yield
console.log('5555')
console.log('6666')
}
const generator = foo()
generator.next() // 返回结果包括 yield 后面的结果值
// 2. 中途中断
// 这种情况下 return 后面的代码都不会执行,因为返回结果都为 { done: true }
function* foo() {
console.log('1111')
console.log('2222')
yield
console.log('3333')
console.log('4444')
return 'aaaa'
console.log('5555')
console.log('6666')
}
const generator = foo()
generator.next()
// 3. 传入参数以及返回结果
/*
* 第一个 yield 中的参数值是由函数中的参数值决定的
* 其他的 yield 参数值是由 next 中传入的参数值决定的
/
function* foo(name1) {
console.log('1111', name1)
console.log('2222', name1)
const name2 = yield 'aaaa'
console.log('3333', name2)
console.log('4444', name2,)
yield
console.log('5555')
console.log('6666')
}
const generator = foo('next1')
generator.next('next2') // 返回结果包括 yield 后面的结果值
3. 生成器替代生成器对象
yield* 可产生一个可迭代对象,这个时候相当于一种yield的语法糖,只不过会依次迭代这个可迭代对象,每次迭代其中的一个值
数组普通方案:
function* createArrayIterator(arr) {
for(let i = 0; i < arr.length; i++) {
yield arr[i]
}
}
语法糖方案:
function* createArrayIterator(arr) {
yield* arr
}
类中的实例方法实现:
class Person {
constructor(friends) {
this.friends = friends
}
*[Symbol.iterator]() {
yield* this.friends
}
}