定义:迭代器是帮助我们对某个数据结构进行遍历的对象。
在javascript中,迭代器也是一个具体的对象,这个对象更需要符合迭代器协议
迭代器协议(iterator protocol):
迭代器协议定义了产生一系列值的标准方式;
在js中这个标准就是一个特定的next方法;
next方法:
示例1:一个简单的迭代器
javascriptconst iterator = {
next: function() {
return { done: true, value: 123}
}
}
上面的iterator就是一个最简单的迭代器,但是我们知道迭代器是帮助我们遍历某个数据结构的,所以这个迭代器看起来是没什么用的。
示例2: 一个能遍历数组的迭代器
javascriptconst names = ['zhangsan', 'lisi', 'wangwu']
let index = 0
const namesIterator = {
next: function() {
if(index < names.length) {
return { done: false, value: names[index++] }
} else {
return { done: true, value: undefined}
}
}
}
上面创建了一个namesIterator迭代器,能对names数组进行迭代遍历,使用方法是一次调用next方法
javascriptconsole.log(namesIterator.next()) // { done: false, vlaue: 'zhangsan' }
console.log(namesIterator.next()) // { done: false, vlaue: 'lisi' }
console.log(namesIterator.next()) // { done: false, vlaue: 'wangwu' }
console.log(namesIterator.next()) // { done: true, value: undefined }
console.log(namesIterator.next()) // { done: true, value: undefined }
到这,我们其实应该对迭代器的定义有了初步的认识了。
可迭代对象:当一个对象实现了可迭代协议(iterable protocol)就是一个可迭代对象 注意不要和迭代器协议(iterator protocol)搞混了。
可迭代协议:要求对象必须实现@@iterator方法,在代码中我们使用Symbol.iterator访问该属性;并且要求这个函数返回一个迭代器
示例3:将示例2转换成一个可迭代对象
javascriptconst iterableObj = {
names: ['zhangsan', 'lisi', 'wangwu'],
[Symbol.iterator]: function() {
let index = 0
return {
next: () => { // 一定要是箭头函数,this指向iterableObj才能访问到names属性
if(index < this.names.length) {
return { done: false, value: this.names[index++] }
} else {
return { done: true, value: undefined}
}
}
}
}
}
上面的iteratorObj就是一个可迭代对象 ,因为它有一个Symbol.iterator属性, 并且返回一个迭代器
使用
JAVASCRIPTconst iterator = iterableObj[Symbol.iterator]() // 调用这个函数返回一个迭代器
console.log(iterator.next()) // { done: false, vlaue: 'zhangsan' }
console.log(iterator.next()) // { done: false, vlaue: 'lisi' }
console.log(iterator.next()) // { done: false, vlaue: 'wangwu' }
console.log(iterator.next()) // { done: true, value: undefined }
console.log(iterator.next()) // { done: true, value: undefined }
for...of
语句可以看成是一种语法糖,这种语法糖的作用是循环调用可迭代对象自定义的迭代器的next方法,当done时false的时候返回value,done是true的时候循环停止。
for...in
语句是遍历一个对象的除Symbol以外的可枚举属性
for...of..可以遍历的东西必须是可迭代对象,之前不懂老是把for...in和for..of...搞混了,会写下面这样的代码
示例4
javascriptconst obj = {
name: 'zhangsan',
age: 20
}
// 输出name age
for(const key in obj) {
console.log(key)
}
// 遍历obj报错 *TypeError: obj is not iterable* 因为obj不是可迭代对象
for(const key of obj) {
console.log({key})
}
// 输出zhangsan lisi wangwu,因为iteratorObj是可迭代对象
for(const key of iteratorObj) {
console.log({key})
}
示例5:arr是一个Array对象,它内部已经实现了 Symbol.iterator方法,所以可以用for...of遍历
javascriptconst arr = ['zhangsan', 'lisi', 'wangwu']
const iterator = arr[Symbol.iterator]()
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
javascript内置创建可迭代对象: Array
,Map
,Set
,String
,TypedArray
,arguments
javascriptconst [name, age] = ['zhangsan', 20]
javascriptconst { name } = obj
定义:生成器是ES6中新增的一种函数控制、使用的方案,它让我们更加灵活的控制函数什么时候执行、暂停执行等。
生成器是和函数结合在一起的,一般我们并不会直接去说生成器,而说生成器函数,因为生成器是由生成器函数生成的
生成器是特殊的迭代器
示例6:一个简单的生成器函数foo,执行返回一个生成器generator
javascriptfunction * foo() {
console.log("step 1")
yield
console.log("step 2")
yield
console.log("step 3")
}
const generator = foo() // 函数内部不执行 返回一个生成器函数
示例7: 生成器函数的执行
javascriptfunction * foo() {
yield 'yield1'
yield 'yield2'
}
const generator = foo() // 函数内部不执行 返回一个生成器函数
//执行第一个yield并暂停
console.log(generator.next()) // { value: 'yeild 1', done: false }
//执行第二个yield并暂停
console.log(generator.next()) // { value: 'yeild 2', done: false }
//执行第三个yield并暂停
console.log(generator.next()) // { value: undefined, done: true }
示例7:
javascriptfunction * foo() {
const next1 = yield 'yeild 1'
console.log({ next1 }) // { next1: 'next1' }
const next2 = yield 'yeild 2'
console.log({ next2 }) // { next2: 'next2' }
}
const generator = foo() // 函数内部不执行 返回一个生成器函数
//执行第一个yield并暂停
console.log(generator.next()) // { value: 'yeild 1', done: false }
//执行第二个yield并暂停
console.log(generator.next('next1')) // { value: 'yeild 2', done: false }
//执行第三个yield并暂停
console.log(generator.next('next2')) // { value: undefined, done: true }
生成器是特殊的迭代器,那么可不可以用来替代迭代器呢,答案是可以的
javascriptfunction createIterator(arr) {
let index = 0
return {
next: () => {
if (index < arr.length) {
return { value: arr[index++], done: false}
} else {
return { value: undefined, done: true}
}
}
}
}
const names = ['zhangsan', 'li', 'wangwu']
const iterator = createIterator(names)
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
上面这是一个生成一个迭代器的函数,其实可以用生成器器代替
javascriptfunction * createIterator(arr) {
for(const item of arr) {
yield item
}
}
const names = ['zhangsan', 'li', 'wangwu']
const iterator = createIterator(names)
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
可以再简化一点
javascriptfunction * createIterator(arr) {
yield* arr
}
const names = ['zhangsan', 'li', 'wangwu']
const iterator = createIterator(names)
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
本文作者:叶继伟
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!