上篇讲了关于手写 Promise , 从类的设计, 构造函数设计, then 方法实现, catch 方法借助 then 方法实现, then 方法的核心优化, 包括多次调用, 链式调用等, 最后再补充了一些常用的类方法, 如 all, allSettled, any 等实现, 整体过程还是比较有难度的, 体现在状态的变更, 代码执行顺序的控制等, 也算是 js 一个重要知识点吧.
本篇则开始学习 js 中的迭代器和生成器, 只有先搞明白这俩兄弟, 才会对后续将 async ... await + Promise 有深刻认知.
认识迭代器
迭代器 (iterator) 是使用户能在容器对象上, 安全, 统一地访问容器元素的方法机制协议, 而无需关系容器内部实现细节
或者说迭代器是一种对象, 它提供了一种按顺序访问集合 (数组, 列表, 链表, 集合, 映射等) 中的每个元素的方法, 而无需让开发者了解其底层实现 (抽象接口). 它通常实现一个 next() 方法, 犯病一个包含两个属性的对象:- {value: 当前值, done: 是否遍历完成 }
复制代码 它本质上是一种设计模式, 在语言中通过接口和协议规范, 在运行时表现为一个具有状态和行为的对象. 可以将它类比为一个地铁的闸机系统:
- 设计模式: "一人一票, 顺序通过"
- 编程规范: 所有地铁站必须刷卡
- 接口定义: 必须实现 validate(cart) 和 open() 方法
- 也是对象: 每个地铁站都有一台闸机
- 数据结构: 不存数据 (乘客), 只控制访问顺序
迭代器的好处或者说应用场景在于:
- **统一接口: **不论遍历字符串, 数组, Map, 自定义结构等, 都可以用 for...of 或 .next() 来遍历
- **延迟计算: **迭代器可以"按需" 生成值, 而非一次性生成所有数据 (生成器)
- 内存提效: 适用于处理大数据流或者无限序列 (斐波那契数列等)
- 解耦结构: 数据结构和遍历元素拆分, 让遍历元素部分由迭代器实现
js 中的迭代器
**在 js 中, 迭代器也是一个具体的对象, 这个对象需要符合迭代器协议: **
- 迭代器协议, 定义了产生一系列值的标准方式
- 在 js 中标准就是一个特定的 next() 方法
这个 next() 方法需要满足如下的要求:
- 是一个无参或者仅一个参数的函数, 返回一个应当拥有如下两个属性的对象
- done (boolean)
- value
- // 迭代器 认识, 也是一个对象
- const names = ['youge', 'cj', 'yaya']
- // 创建一个迭代器对象, 来访问 names 数组
- let index = 0
- const namesIterator = {
- next: function() {
- if (index < names.length) {
- return { done: false, value: names[index++] }
- } else {
- return { done: true, value: undefined }
- }
- }
- }
- // 通过 迭代器的 next() 方法不断去访问数组元素
- console.log(namesIterator.next())
- console.log(namesIterator.next())
- console.log(namesIterator.next())
- console.log(namesIterator.next())
- console.log(namesIterator.next())
- // { done: false, value: 'youge' }
- // { done: false, value: 'cj' }
- // { done: false, value: 'yaya' }
- // { done: true, value: undefined }
- // { done: true, value: undefined }
复制代码 继续来封装一个生成迭代器的函数.- // 生成迭代器的函数, 返回一个对象, 包含 next()
- // 数组迭代器
- function createArrayIterator(arr) {
- let index = 0
- return {
- next: function() {
- if (index < arr.length) {
- return { done: false, value: arr[index++]}
- } else {
- return { done: true, value: undefined }
- }
- }
- }
- }
- const names = ['youge', 'cj', 'yaya']
- const nums = [10, 20, 30]
- const namesIterator = createArrayIterator(names)
- console.log(namesIterator.next())
- console.log(namesIterator.next())
- console.log(namesIterator.next())
- console.log(namesIterator.next())
- // { done: false, value: 'youge' }
- // { done: false, value: 'cj' }
- // { done: false, value: 'yaya' }
- // { done: true, value: undefined }
- // { done: true, value: undefined }
- // nums数组 的迭代器
- const numsIterator = createArrayIterator(nums)
- console.log(numsIterator.next())
- console.log(numsIterator.next())
- console.log(numsIterator.next()) // { done: false, value: 30 }
- console.log(numsIterator.next()) // { done: true, value: undefined }
- // 创建一个无限的迭代器
- function createNumIterator() {
- let index = 0
- return {
- next: function() {
- return { done: false, value: index++ }
- }
- }
- }
- const numIterator = createNumIterator()
- console.log(numIterator.next()) // 0
- console.log(numIterator.next()) // 1
- console.log(numIterator.next()) // 2
- console.log(numIterator.next()) // 3
- console.log(numIterator.next()) // 4
复制代码 可迭代对象
上面认识迭代器的时候, 这个代码分为了 3个部分:
- 创建将要被迭代的数组 (全局)
- 创建一个对象, 里面实现了一个叫 next() 的方法来获取数组数据 (全局)
- 创建一个全局变量 index 来控制 对象 里面的 next 方法, 来访问数组对象
现在要来思考的是, 如何将上面这有紧密联系但是有互相分开的3部分组合到一起, 即统一放在同一个对象中.- // 组合到一起
- const newObj {
- names;
- index;
- obj.next();
- }
复制代码 这个能组合到一起的对象, 就称为 可迭代对象
- 该对象实现了 iterable protocol 可迭代协议
- 该协议必须实现 @@iterator方法, 对应在代码中实现 [Symbol.iterator] 方法即可
- const iterableObje= { [Symbol.iterator]: function() { return 迭代器 } }
复制代码 迭代器
是一个对象, 它实现了 迭代器协议, 表现为该对象有一个 .next() 方法, 并返回 { value, done } 的结构
可迭代对象
也是一个对象, 它实现了 可迭代协议, 表现为该对象有一个 Symbol.ierator 方法, 该方法返回一个 实现了迭代器协议的对象- // 可迭代对象 与 迭代器
- const arr = [1, 2, 3]
- console.log(arr[Symbol.iterator]) // 是个函数, arr 是可迭代对象
- // 数组也是对象, 内置实现了可迭代协议, 可以调用 Symbol.iterator
- // 该方法返回一个迭代器, 可以用它来进行 .next() 获取元素
- const iter = arr[Symbol.iterator]()
- console.log(iter.next())
- console.log(iter.next())
- console.log(iter.next())
- console.log(iter.next())
- // { value: 1, done: false }
- // { value: 2, done: false }
- // { value: 3, done: false }
- // { value: undefined, done: true }
复制代码 对比项可迭代对象(Iterable)迭代器(Iterator)本质对象对象核心特征有 [Symbol.iterator]() 方法有 .next() 方法协议实现 可迭代协议实现 迭代器协议作用能被 for...of、...、yield* 等消费负责实际遍历,返回 {value, done}是否可遍历✅ 可以被遍历✅ 可以被遍历(因为迭代器自己也是可迭代的)典型例子Array, String, Map, Set, argumentsarray[Symbol.iterator]() 的返回值厘清概念之后, 现对之前的数组, 迭代器, 迭代获取数组元素这个过程进行封装, 即将 nams 数组变为可迭代对象.- // 可迭代对象
- const iterableObj = {
- names: ['youge', 'cj', 'yaya'],
- // Symbol.iterator 用 [] 包起来是让其作为字面量对象的 "计算属性"
- [Symbol.iterator]: function() {
- let index = 0
- return {
- next: () => { // 箭头函数无绑定this, 因此 next() 中的 this 会找到父级的 names
- if (index < this.names.length) {
- return { done: false, value: this.names[index++]}
- } else {
- return { done: true, value: undefined}
- }
- }
- }
- }
- }
- // 此时 iterableObj 对象是一个 可迭代对象
- console.log(iterableObj[Symbol.iterator]) // 函数
- // 第一次调用
- const iterator = iterableObj[Symbol.iterator]()
- console.log(iterator.next())
- console.log(iterator.next())
- console.log(iterator.next())
- console.log(iterator.next())
- // 第二次调用
- const iterator2 = iterableObj[Symbol.iterator]()
- console.log(iterator2.next())
- // for ... of 可以遍历, 可迭代对象
- for (const item of iterableObj) {
- console.log(item) // youge, cj, yaya
- }
复制代码 注意点:
- Symbol.iterator 用 "[ ]" 包起来是让其作为字面量对象的 "计算属性"
- 利用箭头函数无绑定 this, 因此 next() 中的 this 会找到父级的 names
- for ... of 可以遍历, 可迭代对象
可见在 js 中的这个 this 的理解是非常重要的, 这里就用到了隐式调用原则嘛.
然后也解决了困扰我很久的问题: js 普通对象为啥不能用 for..of 遍历? 因为普通对象没有实现可迭代协议呀.- // 普通对象不可用 for...of 迭代
- const obj = {
- name: 'youge',
- age: 18
- }
- for (const item of obj) {
- console.log(item)
- }
- // TypeError: obj is not iterable
复制代码 可以理解这个 for...of 也是一个语法糖, 它做的事情就是用迭代器不断调用 .next() 获取元素, 直到 done:true 的时候, 则停止.
内置迭代器对象
像我们常用的 String, Array, Map, Set, arguments, NodeList 等原生对象, 都已实现了可迭代协议, 通过它们所产生的对象, 都是一个可迭代对象.- // 内置了`代器的对象
- // 字符串
- const str = "ab c"
- for (const s of str) {
- console.log(s) // a, b, " "
- }
- // 数组
- const arr = [1, 2]
- const arrIter = arr[Symbol.iterator]()
- console.log(arrIter.next()) // { value: 1, done: false }
- console.log(arrIter.next()) // { value: 2, done: false }
- console.log(arrIter.next()) // { value: undefined, done: true}
- // set / map
- const set = new Set()
- set.add(10)
- set.add(20)
- console.log(set[Symbol.iterator]) // [Function: values]
- for (const item of set) {
- console.log(item) // 10, 20
- }
- // map
- const map = new Map()
- map.set('name', 'youge')
- map.set(() => {}, 'cjj')
- for (const item of map) {
- console.log(item)
- // [ 'name', 'youge' ]
- // [ [Function (anonymous)], 'cjj' ]
- }
- // 函数中的 arguments
- function foo() {
- for (const arg of arguments) {
- console.log(arg) // 1, 2, 3
- }
- }
- foo(1, 2, 3)
复制代码 这些内置对象, 都是可迭代对象, 原因就是它们都实现了 Symbol.iterable 方法, 它会返回迭代器, 内部实现元素的遍历啦.
可迭代对象的应用场景
- js 语法提升: for ...of; 展开表达式; yield; 解构赋值等
- 创建对象时: new Mapt([iterable]); new Set([iterable]), new WeakMap([iterable]) 等
- 方法调用时: Promise.all(iterable); Promise.all(iterable); Array.from(iterable) 等
- // 可迭代对象应用
- // 1. for...of 语法支持
- const arr = [1, 2, 3]
- for (const item of arr) {
- console.log(item) // 1, 2, 3
- }
- // 2. 展开运算符
- const iterableObj = {
- names: ['youge', 'cj', 'yaya'],
- [Symbol.iterator]: function() {
- let index = 0
- return {
- next: () => {
- if (index < this.names.length) {
- return { done: false, value: this.names[index++] }
- } else {
- return { done: true, value: undefined }
- }
- }
- }
- }
- }
- const names = ['bob', 'jack']
- const newNames = [...names, ...iterableObj]
- // [ 'bob', 'jack', 'youge', 'cj', 'yaya' ]
- console.log(newNames)
- // ES9 新增普通对象特性, 虽不可迭代, 但要求支持展开运算符
- // 猜测实现原理 for (const entry obj.entries ) {} 组装 key, value 就搞定了
- const obj = { name: 'youge', age: 18 }
- console.log({...obj}) // { name: 'youge', age: 18 }
- // 3. 解构语法
- const [name1, name2] = names
- console.log(name1, name2) // bob, jack
- const { name, age } = obj
- console.log(name, age) // youge, 18
- // 4. 创建其他对象时
- const set1 = new Set(iterableObj)
- const set2 = new Set(arr)
- // 可迭代对象, 转为数组, 如 arguments
- const arr1 = Array.from(iterableObj)
- // 5. Promise.all(), 传普通值会自动 Promise.resolve(普通值)
- Promise.all(iterableObj).then(res => {
- console.log("res: ", res) // res: [ 'youge', 'cj', 'yaya' ]
- })
复制代码 自定义类的可迭代实现
上述通过 Array, Set, Map, String 等类, 创建出来的对象都是可迭代对象.
现在要来实现一个自己的类, 使其创建出来的对象也是可迭代的, 即在类中实现 [Symbol.iterator] 方法即可
用一个案例: 创建一个 Classroom 的类:
- 每个教室有自己的编号, 楼层, 当前教室的学生
- 教室可以新进来学生 (push)
- 创建的教室对象是可迭代对象
- // 自定义类 - 实现可迭代功能
- class Classroom {
- constructor(id, floor, students) {
- this.id = id
- this.floor = floor
- this.students = students
- }
- entry(newStudent) {
- this.students.push(newStudent)
- }
- }
- const classroom = new Classroom("301", "3楼", ['bob', 'jack'])
- classroom.entry('cj')
- // 需求: 将教室对象都迭代出来
- for (const item of classroom) {
- console.log(item)
- }
复制代码 当前是不能使用 for...of 语法的, 因为我们这个自定义的类, 没有实现可迭代协议. 则我们在对象方法上去实现这个 Symbol.iterator 的方法即可.- // 自定义类 - 实现可迭代功能
- class Classroom {
- constructor(id, floor, students) {
- this.id = id
- this.floor = floor
- this.students = students
- }
- entry(newStudent) {
- this.students.push(newStudent)
- }
- // 让对象可迭代, 添加 [Symbol.iterator] 方法
- [Symbol.iterator]() {
- let index = 0
- return {
- next: () => {
- if (index < this.students.length) {
- return { done: false, value: this.students[index++] }
- } else {
- return { done: true, value: undefined }
- }
- }
- }
- }
- }
- const classroom = new Classroom("301", "3楼", ['bob', 'jack'])
- classroom.entry('cj')
- // 需求: 将教室内学生都迭代出来
- for (const item of classroom) {
- console.log(item) // bob, jack, cj
- }
复制代码 生成器
生成器 (Generator) 是一种特殊的函数, 它可以在函数执行中暂停, 之后再从暂停的地方恢复执行.
它返回一个生成器对象, 该对象既是迭代器, 也是可迭代对象
它提供了一种暂停和恢复函数执行的能力, 是实现惰性求值, 异步编程, 迭代器 等高级功能的核心工具.- // 普通函数的执行, 不能暂停
- function foo() {
- console.log(100)
- console.log(200)
- console.log(300)
- }
- foo()
- // 需求: 在 打印 200 时先暂停, 晚点再往后执行
复制代码 普通函数不能控制 "中途暂停", 此功能在当前知识体系下, 是不能实现的.
生成器函数
生成器函数也是一个函数, 但和普通函数有区别:
- 需要在 function 的后面加一个符号 *
- 可以通过 yield 关键字来控制函数执行流程
- 返回值是一个 生成器对象, 它是一种特殊的迭代器
- // 生成器函数
- function* foo() {
- console.log('函数开始执行...')
- console.log('第一段代码: ', 100)
- yield
- console.log("第二代代码: ", 200)
- yield
- console.log("第三段代码: ", 300)
- yield
- console.log('函数执行结束')
- }
- // 调用 生成器函数时, 会返回一个生成器对象, 特殊迭代器
- const generator = foo()
- // 执行第一段代码, 第一个 yield
- generator.next()
- // 执行第二段代码
- generator.next()
- // 执行第三段代码
- generator.next()
- generator.next() // 函数执行结束
复制代码 即通过 yield 来控制函数的执行顺序, 然后调用生成器函数, 返回的是一个生成器对象, 它是一个特殊的迭代器, 因此可以用它来调用 .next() 方法, 对应于 yield 的分段代码.- // 生成器函数-执行流程
- // 当遇到 yield 时, 暂停函数执行
- // 当遇到 return 时, 生成器停止执行
- function* foo() {
- console.log('函数开始执行...')
- console.log('第一段代码: ', 100)
- yield 111
- console.log("第二代代码: ", 200)
- yield
- console.log("第三段代码: ", 300)
- yield 333
-
- console.log('函数执行结束')
- return 'over'
- }
- // 调用 生成器函数时, 会返回一个生成器对象, 特殊迭代器
- const generator = foo()
- // 生成器对象 的 next() 也有返回值
- console.log(generator.next())
- console.log(generator.next() )
- console.log(generator.next() )
- console.log(generator.next() )// 函数执行结束
- // 函数开始执行...
- // 第一段代码: 100
- // { value: 111, done: false }
- // 第二代代码: 200
- // { value: undefined, done: false }
- // 第三段代码: 300
- // { value: 333, done: false }
- // 函数执行结束
- // { value: 'over', done: true }
复制代码 通过 yield 可以有返回值, 对应到 { value, done} 中. 最后可以进行 return, 值作为最后的 value, done 的值变为 true.
生成器传递参数- next()
在调用 next() 函数时, 传递参数, 则此参数会作为上一个 yield 语句的返回值, 然后在下一个yield 间进行运算
也就是说, 我们是为本次的代码块提供了一个参数值进来.- const generator = foo(5)
- // 生成器对象 的 next() 也有返回值
- // next() 也可以传递参数
- console.log(generator.next())
- // 给第二个 next() 传参
- console.log(generator.next(10) )
复制代码 给第二段代码传参, 则先需要在 第一个段代码的 yield 的地方进行定义和接收, 然后在第二个 yield 后边处理- function* foo() {
- console.log('第一段代码: ', 100)
- const n = yield 100 * num // 这里接收
- console.log("第二代代码: ", 200)
- const count = yield 200 * n // 这里调用
- }
复制代码 同样的做法, 可以给第一个 (很少见) 或者第三个都进行这样的处理:- // 生成器-next() 传递参数
- function* foo(num) {
- console.log('函数开始执行...')
- console.log('第一段代码: ', 100)
- const n = yield 100 * num
- console.log("第二代代码: ", 200)
- const count = yield 200 * n
- console.log("第三段代码: ", 300)
- yield 300 * count
-
- console.log('函数执行结束')
- return 'over'
- }
- const generator = foo(5)
- // 生成器对象 的 next() 也有返回值
- // next() 也可以传递参数
- console.log(generator.next())
- console.log(generator.next(10) )
- console.log(generator.next(20) )
- console.log(generator.next() )
复制代码- 函数开始执行...
- 第一段代码: 100
- { value: 500, done: false }
- 第二代代码: 200
- { value: 2000, done: false }
- 第三段代码: 300
- { value: 6000, done: false }
- 函数执行结束
- { value: 'over', done: true }
复制代码 生成器传递参数- return()
还有一种传参方式是通过 return() 函数, 它会直接终止生成器, 在当前代码块执行之前.
但这样的话就表示生成器函数的结束, 之后调用 next 则不会再继续生成值了.- // 生成器函数-return 函数
- function* foo(num) {
- console.log('函数开始执行...')
- console.log('第一段代码: ', 100)
- const n = yield 100 * num
- console.log("第二代代码: ", 200)
- const count = yield 200 * n
- console.log("第三段代码: ", 300)
- yield 300 * count
-
- console.log('函数执行结束')
- return 'over'
- }
- const generator = foo(5)
- console.log(generator.next())
- // 第二段代码, 执行 return
- console.log(generator.return(222))
- console.log(generator.next(20) )
- console.log(generator.next())
复制代码- 函数开始执行...
- 第一段代码: 100
- { value: 500, done: false }
- { value: 222, done: true }
- { value: undefined, done: true }
- { value: undefined, done: true }
复制代码 则在第二段的时候, 调用 "generator.return(222)" 相当于是在第一段代码执行结束后进行 return- function* foo(num) {
- console.log('函数开始执行...')
- console.log('第一段代码: ', 100)
- const n = yield 100 * num
-
- // 相当于在这里终止了生成器
- return 222
- // 因为 return 了, 则后面的不会再进行 yield 新值了
- console.log("第二代代码: ", 200)
- const count = yield 200 * n
-
- // ....
- }
复制代码 生成器抛出异常 - throw()
除了可以给生成器函数内部传参外, 也可以给生成器函数内部抛出异常.
- 抛异常后, 可以在生成器函数中捕获异常
- 但在 catch 语句中则不能再 yield 新值了, 但在 catch 语句外用 yield 中断语句执行可以
- // 生成器函数-throw() 捕捉异常
- function* foo() {
- console.log('函数开始执行...')
- console.log('第一段代码: ', 100)
- try {
- yield 100
- } catch (err) {
- console.log('捕捉到异常: ', err)
- }
-
- console.log("第二代代码: ", 200)
- const count = yield 200
- console.log("第三段代码: ", 300)
- yield 300 * count
-
- console.log('函数执行结束')
- return 'over'
- }
- const generator = foo()
- console.log(generator.next())
- // 第二段代码, 执行 throw, 则会在第一段代码执行完后就异常了
- console.log(generator.throw('err'))
- // 处理完异常后, 后续逻辑则正常运行
- console.log(generator.next(20))
- console.log(generator.next())
复制代码- 函数开始执行...
- 第一段代码: 100
- { value: 100, done: false }
- 捕捉到异常: err
- 第二代代码: 200
- { value: 200, done: false }
- 第三段代码: 300
- { value: 6000, done: false }
- 函数执行结束
- { value: 'over', done: true }
复制代码 生成器 替代 迭代器使用
生成器是一种特殊的迭代器, 则在一些情况下可以是使用生成器来代替迭代器的.- // 生成器 代替 迭代器
- // 迭代器
- function arrayIterator(arr) {
- let index = 0
- return {
- next: function() {
- if (index < arr.length) {
- return {done: false, value: arr[index++]}
- } else {
- return {done: true, value: undefined}
- }
- }
- }
- }
- const names = ['youge', 'cj', 'yaya']
- const namesIterator = arrayIterator(names)
- console.log(namesIterator.next())
- console.log(namesIterator.next())
- console.log(namesIterator.next())
- // 也可以用生成器替代
- function* arrayGenerator(arr) {
- for (const item of arr) {
- yield item // {value: xxx, done: false}
- }
-
- }
- const namesGenerator = arrayGenerator(names)
-
- console.log(namesGenerator.next())
- console.log(namesGenerator.next())
复制代码 我们还可以使用 yield* 来生成一个可迭代对象.
这时候相当于是一个 yield语法糖, 会以此迭代这个可迭代对象, 每次迭代其中的一个值.- // 生成器 代替 迭代器 yield* 语法糖
- function* arrayGenerator(arr) {
- // yield* 可迭代对象
- yield* arr
- }
- const names = ['youge', 'cj', 'yaya']
- const namesGenerator = arrayGenerator(names)
-
- console.log(namesGenerator.next())
- console.log(namesGenerator.next())
- console.log(namesGenerator.next())
- console.log(namesGenerator.next())
复制代码- { value: 'youge', done: false }
- { value: 'cj', done: false }
- { value: 'yaya', done: false }
- { value: undefined, done: true }
复制代码 来个小案例, 创建一个函数, 这个函数可以迭代一个范围内的数字- // 用生成器代替迭代器
- function* createRangeIterator(start, end) {
- let index = start
- while (index < end) {
- yield index++
- }
- }
- const rangeIterator = createRangeIterator(1, 3)
- console.log(rangeIterator.next())
- console.log(rangeIterator.next())
- console.log(rangeIterator.next())
- // { value: 1, done: false }
- // { value: 2, done: false }
- // { value: undefined, done: true }
- // { value: undefined, done: true }
复制代码 同样的, 对于之前自定义类的迭代器, 也是可以改写为生成器的.- // 自定义类 - 实现可迭代功能
- class Classroom {
- constructor(id, floor, students) {
- this.id = id
- this.floor = floor
- this.students = students
- }
- entry(newStudent) {
- this.students.push(newStudent)
- }
- // 让对象可迭代, 添加 [Symbol.iterator] 方法
- [Symbol.iterator]() {
- let index = 0
- return {
- next: () => {
- if (index < this.students.length) {
- return { done: false, value: this.students[index++] }
- } else {
- return { done: true, value: undefined }
- }
- }
- }
- }
- }
复制代码 现在可以改成这样的:- // 自定义类 - 迭代逻辑, 用生成器替换
- class Classroom {
- constructor(id, floor, students) {
- this.id = id
- this.floor = floor
- this.students = students
- }
- entry(newStudent) {
- this.students.push(newStudent)
- }
- // 用生成器来实现 [Symbol.iterator] 方法
- *[Symbol.iterator]() {
- yield* this.students // 妙呀!
- }
- }
复制代码- // 测试一下
- const classroom = new Classroom("301", "3楼", ['bob', 'jack'])
- classroom.entry('cj')
- // 需求: 将教室对象都迭代出来
- for (const item of classroom) {
- console.log(item)
- }
复制代码 在实际应用中, 能用生成器解决问题, 尽量用它, 就不用自己写迭代器的一通逻辑, 直接用这种大道至简的语法糖:至此, 关于迭代器和生成器的基本使用部分就到这了. 整体操作难度不大, 但是概念特别多, 比如说迭代器, 迭代器对象, 可迭代对象, 生成器, 生成器函数, 生成器是特殊迭代器, 生成器可以在某些情况下替代迭代器, for ...of 的语法糖, yield* 可迭代对象等. 就还是细节很多, 理解为主, 能用就行.
来源:豆瓜网用户自行投稿发布,如果侵权,请联系站长删除 |