# iterator 接口机制
- 概念
- iterator 是一种接口机制,为各种不同的数据结构提供统一的访问机制
- 其工作原理和 C++ 的 iterator 很相似
- 作用
- 为各种数据结构,提供一个统一的、简便的访问接口
- 使得数据结构的成员能够按某种次序排列
- ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要为 for...of 服务
- 工作原理
- 创建一个指针对象,指向数据结构的起始位置
- 第一次调用 next 方法,指针自动指向数据结构的第一个成员
- 接下来不断调用 next 方法,指针会一直往后移动,直到指向最后一个成员
- 每调用 next 方法返回的是一个包含 value 和 done 的对象,
- value 表示当前成员的值,done 对应的布尔值表示当前的数据的结构是否遍历结束
- 当遍历结束的时候返回的 value 值是 undefined,done 值为 false
- 应用
- Array、arguments、set、map、String 等天然具备 iterator 接口(可用 for...of 遍历)
- 扩展
- 使用
解构赋值
以及 三点运算符
时会自动调用 iterator 接口
| |
| |
| function myIterator(arr) { |
| let nextIndex = 0; |
| return { |
| next: function () { |
| return nextIndex < arr.length ? {value: arr[nextIndex++], done: false} : {value: undefined, done: true}; |
| } |
| } |
| } |
| |
| let arr = [1, 2, 3]; |
| |
| let iteratorObj = myIterator(arr); |
| |
| console.log(iteratorObj.next()); |
| |
| console.log(iteratorObj.next()); |
| |
| console.log(iteratorObj.next()); |
| |
| console.log(iteratorObj.next()); |
| |
| |
| let arr3 = [1, 2, 'yain', true]; |
| for(let i of arr3){ |
| console.log(i); |
| } |
| |
| let str = 'abcdefg'; |
| for(let item of str){ |
| console.log(item); |
| } |
| |
| |
| let arr = [2, 3, 4, 5]; |
| let arr2 = [1, ...arr, 6]; |
| |
| console.log(arr2); |
# Generator 函数
- 概念
- ES6 提供的解决异步编程的方案之一
- Generator 函数是一个状态机,内部封装了不同状态的数据,用来生成遍历器对象
- 也称为可暂停函数 (惰性求值),yield 可暂停,next 方法可启动。每次返回的是 yield 后的表达式结果
- 特点
- function 与函数名之间有一个星号
- 内部用 yield 表达式来定义不同的状态
| |
| function* generatorExample(){ |
| let result = yield 'hello'; |
| yield 'generator'; |
| } |
- generator 函数返回的是指针对象(刚刚介绍的 iterator),而不会执行函数内部逻辑
- 调用 next 方法函数内部逻辑开始执行,遇到 yield 表达式停止,返回
{value: yield后的表达式结果/undefined, done: false/true}
- 再次调用 next 方法会从上一次停止时的 yield 处开始,直到最后
- yield 语句返回结果通常为 undefined, 当调用 next 方法时传参内容会作为启动时 yield 语句的返回值
| |
| function* generatorTest() { |
| console.log('函数开始执行'); |
| yield 'hello'; |
| console.log('函数暂停后再次启动'); |
| let result = yield 'generator'; |
| |
| |
| console.log(result); |
| console.log('函数执行完毕'); |
| } |
| |
| let Gt = generatorTest(); |
| |
| console.log(Gt); |
| |
| |
| let result = Gt.next(); |
| |
| console.log(result); |
| |
| result = Gt.next(); |
| |
| console.log(result); |
| result = Gt.next('我被传进去了'); |
| |
| |
| console.log(result); |
# 对象的 Symbol.iterator 属性
之前介绍 iterator 的时候,说过只有 Array、arguments、set、map、String 等天然具备 iterator 接口。也就是说,对象默认没有 iterator 接口,不能使用 for...of 遍历。但是,我们可以借助 Symbol 数据类型为对象添加一个 iterator 接口。
| |
| let myIterable = {}; |
| |
| |
| myIterable[Symbol.iterator] = function* () { |
| yield 1; |
| yield 2; |
| yield 4; |
| }; |
| |
| for(let i of myIterable){ |
| console.log(i); |
| } |
| |
| let obj = [...myIterable]; |
| |
| console.log(obj); |
# Generator 应用案例
之前介绍 Promise 的时候,介绍过如何用 Promise 封装处理 ajax 请求。这里可以用 Generator 函数来实现一下。
- 需求
- 发送 ajax 请求获取新闻内容
- 新闻内容获取成功后再次发送请求,获取对应的新闻评论内容
- 新闻内容获取失败则不需要再次发送请求
| |
| function getNews(url) { |
| $.get(url, function (data) { |
| console.log(data); |
| let commentsUrl = data.commentsUrl; |
| let url = 'http://localhost:3000' + commentsUrl; |
| |
| |
| sx.next(url); |
| }) |
| } |
| |
| function* sendXml() { |
| |
| let url = yield getNews('http://localhost:3000/news?id=2'); |
| yield getNews(url); |
| } |
| |
| |
| let sx = sendXml(); |
| |
| sx.next(); |
# async 函数
- 概念
- 真正意义上去解决异步回调的问题,同步流程表达异步操作
- 本质
- 语法
| async function foo(){ |
| await 异步操作; |
| await 异步操作; |
| } |
- 特点
- 不需要像 Generator 去调用 next 方法,遇到 await 等待,当前的异步操作完成就往下执行
- 返回的总是 Promise 对象,可以用 then 方法进行下一步操作
- async 取代 Generator 函数的星号 *,await 取代 Generator 的 yield
- 语意更为明确
| |
| async function timeout(ms) { |
| return new Promise(resolve => { |
| setTimeout(resolve, ms); |
| }); |
| } |
| |
| |
| async function asyncPrint(value, ms) { |
| console.time('运算时间:') |
| await timeout(ms); |
| console.timeEnd('运算时间:') |
| console.log(value); |
| } |
| |
| console.log(asyncPrint('hello async', 2000)); |
| |
| |
| async function awaitTest() { |
| let result = await Promise.resolve('执行成功'); |
| |
| console.log(result); |
| |
| let result2 = await Promise.reject('执行失败'); |
| |
| console.log(result2); |
| let result3 = await Promise.resolve('还想执行一次'); |
| console.log(result3); |
| } |
| awaitTest(); |
# async 应用案例
依旧是那个获取新闻内容和评论的案例
- 需求
- 发送 ajax 请求获取新闻内容
- 新闻内容获取成功后再次发送请求,获取对应的新闻评论内容
- 新闻内容获取失败则不需要再次发送请求
| |
| async function sendXml(url) { |
| return new Promise((resolve, reject) => { |
| $.ajax({ |
| url, |
| type: 'GET', |
| success: data => resolve(data), |
| error: error => resolve(false) |
| }) |
| }); |
| } |
| async function getNews(url) { |
| let result = await sendXml(url); |
| console.log(result); |
| if (!result) { |
| alert('暂时没有新闻内容'); |
| return; |
| } |
| result = await sendXml('http://localhost:3000' + result.commentsUrl); |
| console.log(result); |
| } |
| getNews('http://localhost:3000/news?id=2'); |
| |
# Class 机制
- 特点
- 通过 class 定义类 / 实现类的继承
- 在类中通过 constructor 定义构造方法
- 通过 new 来创建类的实例
- 通过 extends 来实现类的继承
- 通过 super 调用父类的构造方法
- 重写从父类中继承的一般方法
- 如果之前有了解过 C++ 或 Java 的话,就很好理解这个 Class 了
| class Person { |
| |
| constructor(name, age){ |
| this.name = name; |
| this.age = age; |
| |
| } |
| |
| show(){ |
| console.log(this.name, this.age); |
| } |
| } |
| let person = new Person('yain', 21); |
| |
| person.show(); |
| |
| |
| class sonPerson extends Person{ |
| constructor(name, age, salary) { |
| |
| super(name, age); |
| this.salary = salary; |
| } |
| |
| show(){ |
| console.log(this.name, this.age, this.salary); |
| } |
| } |
| let son = new sonPerson('apple', 22, 10000); |
| |
| son.show(); |