目录1. 什么是迭代器?1.1 迭代器的基本实现1.2 迭代器的封装实现2. 什么是可迭代对象2.1 原生可迭代对象(js内置)2.1.1 部分for of 演示2.1.2 查看内置
概念: 迭代器(iterator),是确使用户可在容器对象(container,例如链表或数组)上遍访的对象[1][2][3],设计人员使用此接口无需关心容器对象的内存分配的实现细节。
JS中的迭代器
其对象返回一个next函数
调用next函数返回一个对象,其对象中包含两个属性done
(完成),它的值为布尔类型,也就是true/false
。
{done:false}
{done:true}
value
(值),它可以返回js中的任何值,TS中表示可为:value:any
类型思考以下代码:
let index = 0
const bears = ['ice', 'panda', 'grizzly']
let iterator = {
next() {
if (index < bears.length) {
return { done: false, value: bears[index++] }
}
return { done: true, value: undefined }
}
}
console.log(iterator.next()) //{ done: false, value: 'ice' }
console.log(iterator.next()) //{ done: false, value: 'panda' }
console.log(iterator.next()) //{ done: false, value: 'grizzly' }
console.log(iterator.next()) //{ done: true, value: undefined }
next
方法,next
方法返回了一个对象,有done
属性和value
属性,且key
的值类型也为boolean
或any
,符合迭代器协议,是一个妥妥的迭代器没跑了。index
和iterator
对象是属于一个整体,我却使用了全局变量,从V8引擎的GC,可达性(也就是标记清除)来看,如果bears = null
,不手动设置为null很有可能会造成内存泄漏,并且内聚性低。very beautiful
,very 优雅。
思考一下代码:
const bears = ['ice', 'panda', 'grizzly']
function createArrIterator(arr) {
let index = 0
let _iterator = {
next() {
if (index < arr.length) {
return { done: false, value: arr[index++] }
}
return { done: true, value: undefined }
}
}
return _iterator
}
let iter = createArrIterator(bears)
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
迭代器对象和可迭代对象是一个不同的东西,虽然它们存在关联,而且面试的时候经常面这些概念,废话不多说,我们直接进入主题。
实现了[Symbol.iterator]为key的方法,且这个方法返回了一个迭代器对象
for of 的时候,其本质就是调用的这个函数,也就是[Symbol.iterator]为key的方法
let str = 'The Three Bears'
const bears = ['ice', 'panda', 'grizzly']
for( let text of str) {
console.log(text) //字符串每个遍历打印
}
for( let bear of bears) {
console.log(bear)
}
//ice panda grizzly
const bears = ['ice', 'panda', 'grizzly']
//数组的Symbol.iterator方法
const iter = bears[Symbol.iterator]()
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
const nickName = 'ice'
//字符串的Symbol.iterator方法
const strIter = nickName[Symbol.iterator]()
console.log(strIter.next())
console.log(strIter.next())
console.log(strIter.next())
console.log(strIter.next())
let info = {
bears: ['ice', 'panda', 'grizzly'],
[Symbol.iterator]: function() {
let index = 0
let _iterator = {
//这里一定要箭头函数,或者手动保存上层作用域的this
next: () => {
if (index < this.bears.length) {
return { done: false, value: this.bears[index++] }
}
return { done: true, value: undefined }
}
}
return _iterator
}
}
let iter = info[Symbol.iterator]()
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
//符合可迭代对象协议 就可以利用 for of 遍历
for (let bear of info) {
console.log(bear)
}
//ice panda grizzly
[Symbol.iterator]
方法,并且这个方法返回了一个迭代器对象。class myInfo {
constructor(name, age, friends) {
this.name = name
this.age = age
this.friends = friends
}
[Symbol.iterator]() {
let index = 0
let _iterator = {
next: () => {
const friends = this.friends
if (index < friends.length) {
return {done: false, value: friends[index++]}
}
return {done: true, value: undefined}
}
}
return _iterator
}
}
const info = new myInfo('ice', 22, ['panda','grizzly'])
for (let bear of info) {
console.log(bear)
}
//panda
//grizzly
friends
进行了迭代,你也可以迭代你想要的一切东西...生成器是es6新增的一种可以对函数控制的方案,能灵活的控制函数的暂停执行,继续执行等。
生成器函数和普通函数的不同
function
定义,生成器函数function*
,要在后面加*
yield
来控制函数的执行function* bar() {
console.log('fn run')
}
bar()
function* bar() {
console.log('fn run')
}
const generator = bar()
console.log(generator.next())
//fn run
//{ value: undefined, done: true }
function* bar() {
console.log('fn run start')
yield 100
console.log('fn run...')
yield 200
console.log('fn run end')
return 300
}
const generator = bar()
//1. 执行到第一个yield,暂停之后,并且把yield的返回值 传入到value中
console.log(generator.next())
//2. 执行到第一个yield,暂停之后,并且把yield的返回值 传入到value中
console.log(generator.next())
//3. 执行剩余代码
console.log(generator.next())
//打印结果:
//fn run start
//{done:false, value: 100}
//fn run...
//{done:false, value: 200}
//fn run end
//{done:true, value: 300}
yield x
,后就会暂停,等待下一次调用next继续往下执行,周而复始,没有了yield
关键字,进行最后一次next调用返回done:true
。我有一个需求,既然生成器能控制函数分段执行,我要你实现一个分段传参。
思考以下代码:
function* bar(nickName) {
const str1 = yield nickName
const str2 = yield str1 + nickName
return str2 + str1 + nickName
}
const generator = bar('ice')
console.log(generator.next())
console.log(generator.next('panda '))
console.log(generator.next('grizzly '))
console.log(generator.next())
// { value: 'ice', done: false }
// { value: 'panda ice', done: false }
// { value: 'grizzly panda ice', done: true }
// { value: undefined, done: true }
前面我们讲到,生成器是一个特殊的迭代器,那生成器必定是可以代替迭代器对象的,思考以下代码。
let bears = ['ice','panda','grizzly']
function* createArrIterator(bears) {
for (let bear of bears) {
yield bear
}
}
const generator = createArrIterator(bears)
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
其实这里还有一种语法糖的写法yield*
思考以下代码:
let bears = ['ice','panda','grizzly']
function* createArrIterator(bears) {
yield* bears
}
const generator = createArrIterator(bears)
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
class myInfo {
constructor(name, age, friends) {
this.name = name
this.age = age
this.friends = friends
}
*[Symbol.iterator]() {
yield* this.friends
}
}
const info = new myInfo('ice', 22, ['panda','grizzly'])
for (let bear of info) {
console.log(bear)
}
//panda
//grizzly
{done:boolean, value:any}
[Symbol.iterator]
方法,并且调用这个方法返回一个迭代器function* bar() {}
这种形式定义yield
关键字可以控制函数分段执行到此这篇关于javascript中的迭代器和可迭代对象与生成器的文章就介绍到这了,更多相关JavaScript迭代器内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: JavaScript中的迭代器和可迭代对象与生成器
本文链接: https://www.lsjlt.com/news/167738.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-01-12
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0