1. 迭代器
迭代器(iterator)是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署iterator接口,就可以完成遍历操作。当需要自定义遍历数据的时候,要想到迭代器。
- es6 创造了一种新的遍历命令for...of循环,iterator接口主要供for...of消费
- 原生具备iterator接口的数据(可用for...if遍历)
Array Arguments Set Map String TypedArray NodeList
- 工作原理
1)(由Symbol.interator创建)创建一个指针对象,指向当前数据结构的起始位置;
2)第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员;
3)接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员;
4)每调用next方法返回一个value和done属性的对象
// 声明一个数组
const test = ['a', 'b', 'c', 'd']
// 使用for of 遍历数组 输出的是键值对的值
for (let v of test) {
console.log(v)
}
// 使用for in 遍历数组 输出的是键值对的序号
for (let v in test) {
console.log(v)
}
数组能够使用for of的原因,是因为__proto__中有iteator的属性。
将iterator取出来手动调用next方法,当调用完数据结构的最后一个成员后,其value值为undefined , 具体的结果为:
let iterator = test[Symbol.iterator]()
// 调用对象的next方法
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
手动书写迭代器,根据自己的需求进行迭代数据。例子如下:
// 例子 -- 当遍历family对象时 输出的是family.persons的值
const family = {
name: '张氏一家',
persons: [
'father Zhang',
'mother Zhang',
'son',
'daughter',
'dog'
],
[Symbol.iterator] () {
let index = 0; // 索引变量
let _this = this
return {
next: function () {
if (index < _this.persons.length) {
index ++ // 指向下一个
return { value: _this.persons[index], done: false}
} else {
return { value: undefined, done: true}
}
}
}
}
}
for (let value of family) {
console.log(value)
}
将代码进行修改:简写function为箭头函数,此时的this就可以直接使用
const family = {
name: '张氏一家',
persons: [
'father Zhang',
'mother Zhang',
'son',
'daughter',
'dog'
],
[Symbol.iterator] () {
let index = 0; // 索引变量
return {
next: () => {
if (index < this.persons.length) {
index ++ // 指向下一个
return { value: this.persons[index], done: false}
} else {
return { value: undefined, done: true}
}
}
}
}
}
推荐一篇文档,关于iterator迭代器: https://segmentfault.com/a/1190000016824284
2. 生成器
生成器函数是 es6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。
- 声明与传统函数不同
function * AAA () {
}
或
function* AAA () {
}
或
function *AAA () {
}
- 执行特殊 ( 借助于 next() 方法执行 )
function * AAA () {
console.log('hello generator !')
}
let iterator = AAA()
console.log(iterator)
// 借助于next()方法执行
iterator.next()
2.1 yield
yield的理解:函数代码的分隔符,三个yield将函数分为了四块。yield 关键字使生成器函数暂停执行,并返回跟在它后面的表达式的当前值。与return类似,但是可以使用next方法让生成器函数继续执行函数yield后面内容,直到遇到yield暂停或return返回或函数执行结束。
yield 后的内容为迭代器中value的值。当next()执行后,会暂行执行,当再次运行next(),会在之前的进度上执行下去。
// yeild 函数代码的分隔符
function * AAA () {
yield 'AAA is a dog'
yield 'aaa is a cat'
yield 'BBB is a tiger'
}
let iterator = AAA()
// 借助于next()方法执行
console.log(iterator.next())
// 遍历
for (let v of AAA()) {
console.log(v)
}
2.2 参数
可以整体传参,在获取迭代器对象的时候传参;也可以通过next()方法进行传参。通过next方法传的参数可以作为上一个yiled的返回值。整体传参,与匿名函数传参相同。代码和效果如下
function * test (arg) {
console.log(arg)
let one = yield 11111
console.log(one)
let two = yield 22222
console.log(two)
let three = yield 33333
console.log(three)
}
// 执行获取迭代器对象
let iterator = test ('param')
console.log(iterator.next())
// next 方法可以传参,传的参数作为上一个yiled的返回值
console.log(iterator.next('我要作为yiled 11111 的返回值'))
console.log(iterator.next('我要作为yiled 22222 的返回值'))
console.log(iterator.next('我要作为yiled 33333 的返回值'))
2.3 异步编程
文件操作、网络操作(ajax, request)、数据库操作等涉及到异步编程。以下代码是一个例子,通过yield控制任务的相继延迟输出,能够解决回调地狱的问题(setTimeout嵌套的现象)。
// 需求:1s后控制台输出111 然后2s后输出222 然后3s后输出333
// 现象:解决回调地狱
// 任务一
function one () {
setTimeout(() => {
console.log(111)
iterator.next()
}, 1000)
}
// 任务二
function two () {
setTimeout(() => {
console.log(222)
iterator.next()
}, 2000)
}
// 任务三
function three () {
setTimeout(() => {
console.log(333)
iterator.next()
}, 3000)
}
function * test () {
yield one()
yield two()
yield three()
}
let iterator = test()
iterator.next()
通过异步获取数据(数据之间关联,比如订单数据在获取用户数据之后获取),其中较难的是数据之间的传递和接收处理,通过next传参的特点进行。例子二如下
// 需求:异步处理 用户数据 订单数据 商品数据,并进行数据之间的传递
// 任务一
function getUsers () {
setTimeout(() => {
let data = '用户数据'
iterator.next(data) // 进行数据传递, 方便操作数据
}, 1000)
}
// 任务二
function getOrders () {
setTimeout(() => {
let data = '订单数据'
iterator.next(data) // 进行数据传递, 方便操作数据
}, 1000)
}
// 任务三
function getGoods () {
setTimeout(() => {
let data = '商品数据'
iterator.next(data) // 进行数据传递, 方便操作数据
}, 1000)
}
function * test () {
let users = yield getUsers() // 接收传递的数据
console.log(users)
let orders = yield getOrders() // 接收传递的数据
console.log(orders)
let goods = yield getGoods() // 接收传递的数据
console.log(goods)
}
let iterator = test()
iterator.next()
进入下一篇 ... ...