45.[前端开发-JavaScript高级]Day10-迭代器-生成器
Iterator-Generator详解
1 迭代器可迭代对象
什么是迭代器?
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>const names = ["abc", "cba", "nba"]// 给数组names创建一个迭代器(迭代器: names的跌大气)let index = 0const namesIterator = {next: function() {// done: Boolean// value: 具体值/undefinedif (index < names.length) {return { done: false, value: names[index++] }} else {return { done: true }}}}console.log(namesIterator.next())console.log(namesIterator.next())console.log(namesIterator.next())console.log(namesIterator.next())// 数组numsconst nums = [100, 24, 55, 66, 86]let indexNum = 0const numsIterator = {next: function() {// done: Boolean// value: 具体值/undefinedif (indexNum < nums.length) {return { done: false, value: nums[indexNum++] }} else {return { done: true }}}}</script></body>
</html>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>const names = ["abc", "cba", "nba"]const nums = [100, 24, 55, 66, 86]// 封装一个函数function createArrayIterator(arr) {let index = 0return {next: function() {if (index < arr.length) {return { done: false, value: arr[index++] }} else {return { done: true }}}}}const namesIterator = createArrayIterator(names)console.log(namesIterator.next())console.log(namesIterator.next())console.log(namesIterator.next())console.log(namesIterator.next())const numsIterator = createArrayIterator(nums)console.log(numsIterator.next())console.log(numsIterator.next())console.log(numsIterator.next())console.log(numsIterator.next())console.log(numsIterator.next())console.log(numsIterator.next())</script></body>
</html>
迭代器的代码练习
可迭代对象
可迭代对象的代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>// 将infos变成一个可迭代对象/*1.必须实现一个特定的函数: [Symbol.iterator]2.这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)*/const infos = {friends: ["kobe", "james", "curry"],[Symbol.iterator]: function() {let index = 0const infosIterator = {next: function() {// done: Boolean// value: 具体值/undefinedif (index < infos.friends.length) {return { done: false, value: infos.friends[index++] }} else {return { done: true }}}}return infosIterator}}// 给infos创建一个迭代器, 迭代infos中的friends// console.log(infosIterator.next())// console.log(infosIterator.next())// console.log(infosIterator.next())// console.log(infosIterator.next())// 可迭代对象必然具备下面的特点// const iterator = infos[Symbol.iterator]()// console.log(iterator.next())// console.log(iterator.next())// console.log(iterator.next())// console.log(iterator.next())// 可迭对象可以进行for of操作for (const item of infos) {console.log(item)}// 可迭代对象必然有一个[Symbol.iterator]函数// 数组是一个可迭代对象const students = ["张三", "李四", "王五"]console.log(students[Symbol.iterator])const studentIterator = students[Symbol.iterator]()console.log(studentIterator.next())console.log(studentIterator.next())console.log(studentIterator.next())console.log(studentIterator.next())</script></body>
</html>
优化
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>// 将infos变成一个可迭代对象/*1.必须实现一个特定的函数: [Symbol.iterator]2.这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)*/// 1.迭代infos中friends// const infos = {// friends: ["kobe", "james", "curry"],// [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// }// }// 2.迭代infos中的key/valueconst infos = {name: "why",age: 18,height: 1.88,[Symbol.iterator]: function() {// const keys = Object.keys(this)// const values = Object.values(this)const entries = Object.entries(this)let index = 0const iterator = {next: function() {if (index < entries.length) {return { done: false, value: entries[index++] }} else {return { done: true }}}}return iterator}}// 给infos创建一个迭代器, 迭代infos中的friends// console.log(infosIterator.next())// console.log(infosIterator.next())// console.log(infosIterator.next())// console.log(infosIterator.next())// 可迭代对象必然具备下面的特点// const iterator = infos[Symbol.iterator]()// console.log(iterator.next())// console.log(iterator.next())// console.log(iterator.next())// console.log(iterator.next())// 可迭对象可以进行for of操作for (const item of infos) {const [key, value] = itemconsole.log(key, value)}</script></body>
</html>
2 原生的迭代器对象
原生迭代器对象
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>// 1.数组// const names = ["abc", "cba", "nba"]// for (const name of names) {// console.log(name)// }// console.log(names[Symbol.iterator]())// 2.Set// const set = new Set(["abc", "cba", "nba"])// for (const item of set) {// console.log(item)// }// const setIterator = set[Symbol.iterator]()// console.log(setIterator.next())// console.log(setIterator.next())// console.log(setIterator.next())// console.log(setIterator.next())// 3.argumentsfunction foo() {for (const arg of arguments) {console.log(arg)}}foo(123, 321, 111, 222)</script></body>
</html>
可迭代对象的应用
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>// 1.用在特定的语法上const names = ["abc", "cba", "nba"]const info = {name: "why",age: 18,height: 1.88,[Symbol.iterator]: function() {const values = Object.values(this)let index = 0const iterator = {next: function() {if (index < values.length) {return { done: false, value: values[index++] }} else {return { done: true }}}}return iterator}}function foo(arg1, arg2, arg3) {console.log(arg1, arg2, arg3)}foo(...info)// 2.一些类的构造方法中, 也是传入的可迭代对象const set = new Set(["aaa", "bbb", "ccc"])const set2 = new Set("abc")console.log(set2)const set3 = new Set(info)console.log(set3)// 3.一些常用的方法const p1 = Promise.resolve("aaaa")const p2 = Promise.resolve("aaaa")const p3 = Promise.resolve("aaaa")const pSet = new Set()pSet.add(p1)pSet.add(p2)pSet.add(p3)Promise.all(pSet).then(res => {console.log("res:", res)})function bar() {// console.log(arguments)// 将arguments转成Array类型const arr = Array.from(arguments)console.log(arr)}bar(111, 222, 333)</script></body>
</html>
3 自定义类的迭代器
自定义类的迭代
自定义类的迭代实现
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>class Person {constructor(name, age, height, friends) {this.name = namethis.age = agethis.height = heightthis.friends = friends}// 实例方法running() {}[Symbol.iterator]() {let index = 0const iterator = {next: () => {if (index < this.friends.length) {return { done: false, value: this.friends[index++] }} else {return { done: true }}}}return iterator}}const p1 = new Person("why", 18, 1.88, ["curry", "kobe", "james", "tatumu"])const p2 = new Person("kobe", 30, 1.98, ["curry", "james", "aonier", "weide"])for (const item of p2) {console.log(item)}</script></body>
</html>
迭代器的中断
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>class Person {constructor(name, age, height, friends) {this.name = namethis.age = agethis.height = heightthis.friends = friends}// 实例方法running() {}[Symbol.iterator]() {let index = 0const iterator = {next: () => {if (index < this.friends.length) {return { done: false, value: this.friends[index++] }} else {return { done: true }}},return: () => {console.log("监听到迭代器中断了")return { done: true }}}return iterator}}const p1 = new Person("why", 18, 1.88, ["curry", "kobe", "james", "tatumu"])for (const item of p1) {console.log(item)if (item === "kobe") {break}}</script></body>
</html>
4 生成器理解和作用
什么是生成器?
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>/*生成器函数: 1.function后面会跟上符号: *2.代码的执行可以被yield控制3.生成器函数默认在执行时, 返回一个生成器对象* 要想执行函数内部的代码, 需要生成器对象, 调用它的next操作* 当遇到yield时, 就会中断执行*/// 1.定义了一个生成器函数function* foo() {console.log("1111")console.log("2222")yieldconsole.log("3333")console.log("4444")yieldconsole.log("5555")console.log("6666")}// 2.调用生成器函数, 返回一个 生成器对象const generator = foo()// 调用next方法generator.next()generator.next()generator.next()</script></body>
</html>
生成器函数执行
生成器传递参数 – next函数
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>// const names = ["abc", "cba", "nba"]// const iterator = names[Symbol.iterator]()// console.log(iterator.next())/*生成器函数: 1.function后面会跟上符号: *2.代码的执行可以被yield控制3.生成器函数默认在执行时, 返回一个生成器对象* 要想执行函数内部的代码, 需要生成器对象, 调用它的next操作* 当遇到yield时, 就会中断执行*/// 1.定义了一个生成器函数function* foo(name1) {console.log("执行内部代码:1111", name1)console.log("执行内部代码:2222", name1)const name2 = yield "aaaa"console.log("执行内部代码:3333", name2)console.log("执行内部代码:4444", name2)const name3 = yield "bbbb"// return "bbbb"console.log("执行内部代码:5555", name3)console.log("执行内部代码:6666", name3)yield "cccc"return undefined}// 2.调用生成器函数, 返回一个 生成器对象const generator = foo("next1")// 调用next方法// console.log(generator.next()) // { done: false, value: "aaaa" }// console.log(generator.next()) // { done: false, value: "bbbb" }// console.log(generator.next()) // { done: false, value: "cccc" }// console.log(generator.next()) // {done: true, value: undefined}// 3.在中间位置直接return, 结果// console.log(generator.next()) // { done: false, value: "aaaa" }// console.log(generator.next()) // { done: true, value: "bbbb" }// console.log(generator.next()) // { done: true, value: undefined }// console.log(generator.next()) // { done: true, value: undefined }// console.log(generator.next()) // { done: true, value: undefined }// console.log(generator.next()) // { done: true, value: undefined }// 4.给函数每次执行的时候, 传入参数console.log(generator.next())console.log(generator.next("next2"))console.log(generator.next("next3"))// console.log(generator.next())</script></body>
</html>
生成器提前结束 – return函数
生成器抛出异常 – throw函数
生成器替代迭代器
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>// 1.对之前的代码进行重构(用生成器函数)const names = ["abc", "cba", "nba"]const nums = [100, 22, 66, 88, 55]function* createArrayIterator(arr) {for (let i = 0; i < arr.length; i++) {yield arr[i]}// yield arr[0]// yield arr[1]// yield arr[2]// return undefined}// const namesIterator = createArrayIterator(names)// console.log(namesIterator.next())// console.log(namesIterator.next())// console.log(namesIterator.next())// console.log(namesIterator.next())// const numsIterator = createArrayIterator(nums)// console.log(numsIterator.next())// console.log(numsIterator.next())// console.log(numsIterator.next())// console.log(numsIterator.next())// console.log(numsIterator.next())// console.log(numsIterator.next())// 2.生成器函数, 可以生成某个范围的值// [3, 9)function* createRangeGenerator(start, end) {for (let i = start; i < end; i++) {yield i}}const rangeGen = createRangeGenerator(3, 9)console.log(rangeGen.next())console.log(rangeGen.next())console.log(rangeGen.next())console.log(rangeGen.next())console.log(rangeGen.next())console.log(rangeGen.next())console.log(rangeGen.next())console.log(rangeGen.next())</script></body>
</html>
5 自定义生成器方案
自定义类迭代 – 生成器实现
对生成器的操作
6 异步处理方案解析
异步处理方案
Generator方案
自动执行generator函数
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>// 封装请求的方法: url -> promise(result)function requestData(url) {return new Promise((resolve, reject) => {setTimeout(() => {resolve(url)}, 2000)})}// 1.发送一次网络请求// requestData("http://why").then(res => {// console.log("res:", res)// })/*需求: 1.发送一次网络请求, 等到这次网络请求的结果2.发送第二次网络请求, 等待这次网络请求的结果3.发送第三次网络请求, 等待这次网络请求的结果*/// 方式一: 层层嵌套(回调地狱 callback hell)// function getData() {// // 1.第一次请求// requestData("why").then(res1 => {// console.log("第一次结果:", res1)// // 2.第二次请求// requestData(res1 + "kobe").then(res2 => {// console.log("第二次结果:", res2)// // 3.第三次请求// requestData(res2 + "james").then(res3 => {// console.log("第三次结果:", res3)// })// })// })// }// 方式二: 使用Promise进行重构(解决回调地狱)// 链式调用// function getData() {// requestData("why").then(res1 => {// console.log("第一次结果:", res1)// return requestData(res1 + "kobe")// }).then(res2 => {// console.log("第二次结果:", res2)// return requestData(res2 + "james")// }).then(res3 => {// console.log("第三次结果:", res3)// })// }// 方式三: 最终代码// function* getData() {// const res1 = yield requestData("why")// console.log("res1:", res1)// const res2 = yield requestData(res1 + "kobe")// console.log("res2:", res2)// const res3 = yield requestData(res2 + "james")// console.log("res3:", res3)// }// const generator = getData()// generator.next().value.then(res1 => {// generator.next(res1).value.then(res2 => {// generator.next(res2).value.then(res3 => {// generator.next(res3)// })// })// })// 方式四: async/await的解决方案async function getData() {const res1 = await requestData("why")console.log("res1:", res1)const res2 = await requestData(res1 + "kobe")console.log("res2:", res2)const res3 = await requestData(res2 + "james")console.log("res3:", res3)}const generator = getData()</script></body>
</html>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><script>// 封装请求的方法: url -> promise(result)function requestData(url) {return new Promise((resolve, reject) => {setTimeout(() => {resolve(url)}, 2000)})}// 生成器的处理方案function* getData() {const res1 = yield requestData("why")console.log("res1:", res1)const res2 = yield requestData(res1 + "kobe")console.log("res2:", res2)const res3 = yield requestData(res2 + "james")console.log("res3:", res3)const res4 = yield requestData(res3 + "curry")console.log("res4:", res4)const res5 = yield requestData(res4 + "tatumu")console.log("res5:", res5)}// const generator = getData()// generator.next().value.then(res1 => {// generator.next(res1).value.then(res2 => {// generator.next(res2).value.then(res3 => {// generator.next(res3).value.then(res4 => {// generator.next(res4)// })// })// })// })// 自动化执行生成器函数(了解)function execGenFn(genFn) {// 1.获取对应函数的generatorconst generator = genFn()// 2.定义一个递归函数function exec(res) {// result -> { done: true/false, value: 值/undefined }const result = generator.next(res)if (result.done) returnresult.value.then(res => {exec(res)})}// 3.执行递归函数exec()}execGenFn(getData)</script></body>
</html>