From 51851122759d70bb2b72a1486c08926e3fa9b9fe Mon Sep 17 00:00:00 2001 From: Hacker-C <1507559148@qq.com> Date: Thu, 2 Jun 2022 23:55:07 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E6=B7=BB=E5=8A=A0=E8=BF=AD?= =?UTF-8?q?=E4=BB=A3=E5=99=A8=E4=B8=8E=E7=94=9F=E6=88=90=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- JS-Advance/_sidebar.md | 3 +- JS-Advance/ch05.md | 271 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 JS-Advance/ch05.md diff --git a/JS-Advance/_sidebar.md b/JS-Advance/_sidebar.md index 8b8d60f..04925b6 100644 --- a/JS-Advance/_sidebar.md +++ b/JS-Advance/_sidebar.md @@ -2,4 +2,5 @@ * [ch01. JS 面向对象](JS-Advance/ch01) * [ch02. 构造函数和原型](JS-Advance/ch02) * [ch03. 函数进阶](JS-Advance/ch03) - * [ch04. 正则表达式](JS-Advance/ch04) \ No newline at end of file + * [ch04. 正则表达式](JS-Advance/ch04) + * [ch05. 迭代器与生成器](JS-Advance/ch05) \ No newline at end of file diff --git a/JS-Advance/ch05.md b/JS-Advance/ch05.md new file mode 100644 index 0000000..0960dc7 --- /dev/null +++ b/JS-Advance/ch05.md @@ -0,0 +1,271 @@ +# (五)迭代器与生成器 + +## 1. 迭代器 + +### 1.1 什么是迭代器 + +- 宏观上来讲,迭代器的定义我们可以看出来,迭代器是 **帮助我们对某个数据结构进行遍历的对象**,无需关心内部实现,只需要能使用其接口和特性即可。 +- 微观上来讲(JS 角度),**迭代器是一个具体的对象**,这个对象需要符合 **迭代器协议(iterator protocol)**。 + +### 1.2 迭代器协议 + +- 迭代器协议定义了产生一系列值(无论是有限还是无限个)的标准方式 +- 在 JS 中这个标准就是一个特定的 `next` 方法; + +### 1.3 next 函数(方法) + +`next` 是一个无参或者一个参数的函数,返回一个具有两个属性(`done` 和 `value`)的对象。 + +```js +next: function() { + return { + done: boolean, + value: any + } +} +``` + +返回的对象属性: +- `done`:`true` 表示迭代结束,`flase` 未结束。 +- `value`: 本次迭代的值。 + +### 1.4 举例:封装一个迭代器函数 + +```js +const colors = ['red', 'pink', 'green'] +const nums = [100, 200, 300] + +const iteratorFunc = arr => { + let index = 0 + return { + next() { + if (index < arr.length) { + return { done: false, value: arr[index++] } + } + return { done: true, value: undefined } + } + } +} + +const colorsIterator = iteratorFunc(colors) +const numsIterator = iteratorFunc(nums) + +console.log(colorsIterator.next()) +console.log(colorsIterator.next()) +console.log(colorsIterator.next()) +console.log(colorsIterator.next()) + +console.log(numsIterator.next()) +console.log(numsIterator.next()) +console.log(numsIterator.next()) +console.log(numsIterator.next()) +``` + +### 1.5 可迭代对象 + +- 当一个对象实现了 **iterable protocol 协议** 时,它就是一个可迭代对象。 +- 这个对象的要求是必须实现 `@@iterator` 方法,在代码中我们使用 `Symbol.iterator` 访问该属性 + +#### 如何定义一个可迭代对象 +- 给该对象添加 `[Symbol.iterator](){}` 函数(方法)。 + +#### 可迭代对象有什么用 +- 可迭代对象为可迭代特性服务,也就是说,一个对象实现了可迭代性,那么他就具有一些列可迭代对象所具有的一切特性。 + +- JavaScript中语法:`for ... of`、展开语法(spread syntax)、`yield*`(后面讲)、解构赋值(Destructuring_assignment); +- 创建一些对象时:`new Map([Iterable])`、`new WeakMap([iterable])`、`new Set([iterable])`、`new WeakSet([iterable])`; +- 一些方法的调用:`Promise.all(iterable)`、`Promise.race(iterable)`、`Array.from(iterable)`; + + +#### 一个对象具有可迭代特性的条件 + +- 底层实现了可迭代方法,JS 或者就是 `[Symbol.iterator](){}`,例如数组、字符串、类数组、`Map`、`Set`、`NodeList` 等。检测是否是可迭代对象: +```js +Array.prototype[Symbol.iterator]; +String.prototype[Symbol.iterator]; +Map.prototype[Symbol.iterator]; +Set.prototype[Symbol.iterator]; +``` + +> [!TIP] 一般对象没有实现 `[Symbol.iterator]()`,但 ES9 底层做了处理,**让对象也支持解构赋值和扩展运算符**。 + +#### 创建一个可迭代对象 + +```js +const iterableObj = { + colors: ['red', 'green', 'orange'], + [Symbol.iterator]() { + let index = 0 + return { + next: () => { + if (index < this.colors.length) { + return { done: false, value: this.colors[index++] } + } + return { done: true, value: undefined } + } + } + } +} + +// 1、let ... of ... +for (let color of iterableObj) { + console.log(color) +} +// 2、spread +console.log([...iterableObj]) +// 3、distructing assignment +const [red] = iterableObj +console.log(red) +// 4、new Set +console.log(new Set(iterableObj)) +// 5、Array.from +console.log(Array.from(iterableObj)) +// 6、Promise.all() +Promise.all(iterableObj).then(res => { + console.log(res) +}) +``` + +## 2. 生成器 + +### 2.1 什么是生成器 + +- 生成器是一个函数,能让我们更加方便的控制函数的暂停、继续执行。 +- 生成器是一种特殊的迭代器,一般可以替代迭代器,简化代码 +- 生成器的返回值还是一个生成器(Generator) + +### 2.2 生成器替代迭代器的三种方法 + +```js +// 生成器是一种特殊的迭代器,所以可以代替迭代器 +function* createIterableArray(arr) { + // 1、写法1 + // for (const e of arr) { + // yield e + // } + // 2、写法2 + // yield arr[0] + // yield arr[1] + // yield arr[2] + // 3、写法3 + yield* arr +} + +const names = ['peter', 'jack', 'julia'] +const namesIterator = createIterableArray(names) + +for (let item of namesIterator) { + console.log(item) +} +``` + +### 2.3 async/await 与 生成器 + +在 `async/await` 出现之前,回调地狱问题的解决是靠生成器解决的。 `async/await` 的原理就是生成器。 + +模拟请求: +```js +// request.js +function requestData(url) { + // 异步请求的代码会被放入到executor中 + return new Promise((resolve, reject) => { + // 模拟网络请求 + setTimeout(() => { + // 拿到请求的结果 + resolve(url) + }, 2000); + }) +} +``` + +需求: +- url: why -> res: why +- url: res + "aaa" -> res: whyaaa +- url: res + "bbb" => res: whyaaabbb + +1. 第一种方案: 多次回调 + +```js +// 回调地狱 +requestData("why").then(res => { + requestData(res + "aaa").then(res => { + requestData(res + "bbb").then(res => { + console.log(res) + }) + }) +}) +``` + +2. 第二种方案: Promise中then的返回值来解决 + +```js +requestData("why").then(res => { + return requestData(res + "aaa") +}).then(res => { + return requestData(res + "bbb") +}).then(res => { + console.log(res) +}) +``` + +3. 第三种方案: Promise + generator实现 + +```js +function* getData() { + const res1 = yield requestData("why") + const res2 = yield requestData(res1 + "aaa") + const res3 = yield requestData(res2 + "bbb") + const res4 = yield requestData(res3 + "ccc") + console.log(res4) +} + +// 1> 手动执行生成器函数 +// const generator = getData() +// generator.next().value.then(res => { +// generator.next(res).value.then(res => { +// generator.next(res).value.then(res => { +// generator.next(res) +// }) +// }) +// }) + +// 2> 自己封装了一个自动执行的函数 +function execGenerator(genFn) { + const generator = genFn() + function exec(res) { + const result = generator.next(res) + if (result.done) { + return result.value + } + result.value.then(res => { + exec(res) + }) + } + exec() +} + +execGenerator(getData) +``` + +4. 第四种方案: async/await + +```js +async function getData() { + const res1 = await requestData("why") + const res2 = await requestData(res1 + "aaa") + const res3 = await requestData(res2 + "bbb") + const res4 = await requestData(res3 + "ccc") + console.log(res4) +} +getData() +``` + +## 3. 迭代器与生成器问题 + +实现以下效果: +```bash +>>> [...5] +[1, 2, 3, 4, 5] +``` + +答案解析:http://idk-js.mphy.top/JS/JavaScript.html#_11-10 \ No newline at end of file