迭代器
一、知识背景
- 什么是迭代器
迭代器就是在一个数据集合中不断取出数据的过程 - 迭代和遍历的区别
- 遍历是把所有数据都取出
- 迭代器注重的是依次取出数据,它不会在意有多少数据,也不会保证能够取出多少或者能够把数据都取完。比如斐波那契额数列,就可以使用迭代器进行无限取值。
- 那么,什么是迭代器呢?
对整个迭代过程的封装,不同的语言有不同的表现形式。通常是一个对象 - 迭代模式
一个设计模式,用于统一迭代过程,并规范了迭代器规格- 迭代器应该具有得到下一个数据的能力
- 迭代器应该具有判断是否还有后续数据的能力
二、ES6里的迭代器
JS中规定,如果一个对象具有next方法,并且该方法返回一个对象,则该对象的格式如下,则认为该对象是一个迭代器。
const obj={next(){retrun{value:xxx, // 值done:xxx// 是否迭代完成}}
}
- next方法:用于得到下一批数据
- 返回的对象
- value:下一个数据的值
- done:布尔值,是否完成迭代
三、迭代器创建函数
这个知识点分两个方面来分享 1. 迭代对象内置的迭代器创建函数 2.创建自定义的可迭代对象
3.1、 迭代对象内置的迭代器创建函数
首先,我们需要搞懂什么是迭代器创建函数?
-
ES6规定,如果一个对象具有知名符号属性
[Symbol.iterator]
,并且属性是一个迭代器创建函数,则该对象是可迭代的(iterable)- 迭代器(iterator):一个具有next方法的对象,next方法返回下一个数据并且能指示是否迭代完成
- 迭代器创建函数(iterator create):一个返回迭代器的函数
js中的可迭代对象有很多,例如数组,集合,映射,类数组,字符串等,以数组为例
const arr=[1,3,4,5,6]console.log(arr)
执行数组中的迭代器
// 数组
const arr = [1, 2, 3, 4, 5];
// 数组中内置的迭代器创建函数
const iterator = arr[Symbol.iterator]()
// 执行迭代器
iterator.next()
执行类数组中的迭代器,例如 document.querySelectorAll
// 类数组内置的迭代器
const divs=document.querySelectorAll('div')
const iterator=divs[Sysbol.iterator]()
iterator.next()
3.2、 普通对象自定义创建 迭代器创建函数
通常,我们使用for of
循环遍历可迭代对象
// 迭代完成后循环结束
for(const item in iterable){// iterable:可迭代对象// item 每次迭代得到的数据
}
可以发现,forof
是无法遍历普通对象的,那是因为普通对象不是迭代对象,没有迭代器创建函数和[Symbol.iterator]
属性,如果我把这个属性给它加上,普通对象是否会成为迭代对象,从而被forof遍历
呢?
// 自定义的可迭代对象
var obj = {
a:1,
b:2,[Symbol.iterator]() {return {next() {return {value: 1,done: false}}}}
}
for(const item of obj){console.log(item)
}
结果发现,普通对象是可以通过添加迭代创建函数的方式成为迭代对象的,forof
会不断的获取 迭代器中的value值,只要done不为false,就会一直无限取下去。
生成器
一、知识背景
-
什么是生成器?
生成器是一个通过构造函数Generator创建的,也是一个对象,但是无法自己new,只能js引起内部去使用;生成器即是一个迭代器,同事也是一个迭代对象。 -
如何创建一个生成器?
生成器的创建必须使用生成器函数 (Generator Function),返回的是一个生成器对象
-
如何书写一个生成器函数呢?
// 这是一个生成器函数,该函数一定返回一个生成器function *method(){}function* method(){}{*method(){}}*methods=()=>{}
-
生成器函数是如何执行的?
-
生成器函数内部是给生成器每次迭代提供数据的,生成的数据需要放在
yield
后,才能被迭代出来function* test() {console.log('aaaa') }const generator = test()console.log(generator.next()) // aaaa { value: undefined, done: true }
-
yield
是一个关键词,该关键词只能在生成函数的内部使用,意思是 “产生” 一个迭代数据 -
每次调用生成器的next方法,生成器将运行到下一个
yield
的位置function* test() {console.log('第一次运行')yield 1; //产生的迭代数据console.log('第二次运行')yield 2;//产生的迭代数据console.log('第三次运行')}const generator = test()console.log(generator.next()) // 第一次运行 { value: 1, done: false }console.log(generator.next()) // 第二次运行 { value: 2, done: false }console.log(generator.next()) // 第三次运行 { value: undefined, done: true }
-
生成器可以有返回值
return
返回值出现在当迭代器next方法中的done为true时的 value中function* test() {console.log('第一次运行')yield 1; //产生的迭代数据console.log('第二次运行')yield 2;//产生的迭代数据console.log('第三次运行')return 10; //函数结束,迭代结束,所以迭代器第一次done为true 的value值可以为10 }const generator = test()console.log(generator.next()) // 第一次运行 { value: 1, done: false }console.log(generator.next()) // 第二次运行 { value: 2, done: false }console.log(generator.next()) // 第三次运行 { value: 10, done: true }console.log(generator.next()) / { value: undefined, done: true }
-
调用
next(参数)
方法传值,参数会传给第一次next后的yield,所以第一次调用next()
,传参是没有意思的function* test() {let info = yield 1 // { value: 1, done: false }console.log(info) // 5info = yield 2 + info // { value: 7, done: false }console.log(info)}const generator = test()console.log(generator.next(111)) // { value: 1, done: false }console.log(generator.next(5)) // { value: 7, done: false }
-
在生成器内部调用其他生成器的函数的迭代数据,注意调用时要加
*
fucntion *a(yield 'a'yield 'b')function *test(){// a() 返回一个生成器对象// yield a() 迭代一个生成器对象yield *a()yield 1yield 2yield 3} const generator = test()console.log(generator.next()) // { value: 'a', done: false } // 会先迭代a方法里的数据
-
二、 生成器常见的api使用方法
除了next方法,下面再接收两个用的比较多的方法
return方法
return方法,调用该方法,可以手动结束整个迭代,后面再次调用next方法时,value值为 undefined
function* test() {yield 1yield 2yield 3}const generator = test()console.log(generator.next()) // { value: 1, done: false }console.log(generator.return()) // { value: undefined, done: true }console.log(generator.next()) // { value: undefined, done: true }console.log(generator.next()) // { value: undefined, done: true }console.log(generator.next()) // { value: undefined, done: true }// return 也可以传参数console.log(generator.return(5)) // { value: 5, done: true }
throw方法
throw方法,调用该方法,可以手动抛出一个错误,从而阻止后面数据的迭代
function* test(){yield 1yield 2yield 3
}
const generator = test()
console.log(generator.next()) // { value: 1, done: false }
console.log(generator.throw(new Error('123'))) // 在 yield 1 报错
console.log(generator.next()) // 不运行
console.log(generator.next()) // 不运行