JS迭代与遍历有何区别,迭代器的用法是什么
Admin 2022-08-22 群英技术资讯 1057 次浏览
这篇文章主要讲解了“JS迭代与遍历有何区别,迭代器的用法是什么”,文中的讲解内容简单、清晰、详细,对大家学习或是工作可能会有一定的帮助,希望大家阅读完这篇文章能有所收获。下面就请大家跟着小编的思路一起来学习一下吧。
迭代就是指可以从一个数据集中按照一定的顺序,不断取出数据的过程。
那么迭代和遍历有啥子区别呢?
在JavaScript中,迭代器是能调用 next方法实现迭代的一个对象,该方法返回一个具有两个属性的对象。
value:可迭代对象的下一个值 done:表示是否已经取出所有的数据了。 false表示还有数据, true表示后面已经没有数据了。通过可迭代对象中的迭代器工厂函数 Symbol.iterator来生成迭代器。
const arr = []console.log(arr)

const arr = [1, 2, 3]
const iter1 = arr[Symbol.iterator]() // 通过迭代器工厂函数` Symbol.iterator`来生成迭代器。
console.log(iter1)
console.log(iter1.next())
console.log(iter1.next())
console.log(iter1.next())
console.log(iter1.next())
console.log('%c%s', 'color:red;font-size:24px;', '================')
const mymap = new Map()
mymap.set('name', 'clz')
mymap.set('age', 21)
const iter2 = mymap[Symbol.iterator]() // 通过迭代器工厂函数` Symbol.iterator`来生成迭代器。
console.log(iter2)
console.log(iter2.next())
console.log(iter2.next())
console.log(iter2.next())
可以发现,迭代器是取完最后一个值之后,即迭代器下一个值 value为 undefined时,完成。
但是,上面的说法并不是很准确,并不是迭代器下一个值 value为 undefined时,就完成的。还需要判断是不是真的没有值,还是是可迭代对象里就有一个值为 undefined。如果是可迭代对象里有一个值为 undefined的情况,那么此时还是不会变成完成状态。
const arr = [1, 2, 3, undefined] const iter1 = arr[Symbol.iterator]() // 通过迭代器工厂函数` Symbol.iterator`来生成迭代器。 console.log(iter1) console.log(iter1.next()) console.log(iter1.next()) console.log(iter1.next()) console.log(iter1.next()) console.log(iter1.next())

可以多次调用迭代器工厂函数来生成多个迭代器,每个迭代器都表示对可迭代对象的一次性有序遍历。不同迭代器之间互不干扰,只会独立地遍历可迭代对象。
const arr = [1, 2, 3]
const iter1 = arr[Symbol.iterator]() // 通过迭代器工厂函数` Symbol.iterator`来生成迭代器。
const iter2 = arr[Symbol.iterator]()
console.log('迭代器1:', iter1.next())
console.log('迭代器2:', iter2.next())
console.log('迭代器1:', iter1.next())
console.log('迭代器2:', iter2.next())
const arr = [1, 2, 3]
const iter = arr[Symbol.iterator]()
for (const i of iter) {
console.log(i) // 依次输出1、2、3
}如果可迭代对象在迭代期间被修改了,迭代器得到的结果也会是修改后的。
const arr = [1, 2, 3] console.log(arr) const iter = arr[Symbol.iterator]() console.log(iter.next()) arr[1] = 999 console.log(iter.next()) console.log(iter.next())

当我们迭代到 done: true之后,再调用next是不是会报错,或者不返回任何内容呢?
然而,并不是,迭代器会处于一种完成但并不完成的状态, done: true表示已经完成了,但是后续还能一直调用 next,虽然得到的结果一直都会是 { value: undefined, done: true }。这就是为什么说完成但并不完成。
const arr = [1, 2, 3] const iter = arr[Symbol.iterator]() console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next())

从上面的例子中,我们就可以知道是通过通过迭代器工厂函数 Symbol.iterator来生成迭代器,所以我们需要实现一个迭代器迭代器工厂函数,然后迭代器可以调用 next方法,所以还需要实现一个 next方法,至于迭代器工厂函数,实际上直接返回实例 this。
计数器例子:
class Counter {
constructor(limit) {
this.count = 1
this.limit = limit }
next() {
if (this.count <= this.limit) {
return {
done: false,
value: this.count++
}
} else {
return { done: true, value: undefined }
}
}
[Symbol.iterator]() {
return this
}}const counter = new Counter(3) const iter = counter[Symbol.iterator]() console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next()) console.log(iter.next())

乍一看,没啥问题,但是如果我们使用 for-of来遍历就能发现问题。
const counter = new Counter(3)for (let i of counter) {
console.log(i)}console.log('另一轮迭代:')for (let i of counter) {
console.log(i)}
使用 for-of循环也变成一次性的了。这是因为 count是该实例的变量,所以两次迭代都是使用的那一个变量,但是该变量第一次循环完之后,就已经超过限制了,所以再次使用 for-of循环就得不到任何的结果了。
可以把 count变量放在闭包里,然后通过闭包返回迭代器,这样子每创建一个迭代器都会对应一个新的计数器。
class Counter {
constructor(limit) {
this.limit = limit }
[Symbol.iterator]() {
let count = 1
const limit = this.limit return {
// 迭代器工厂函数必须要要返回一个带有next方法的对象,因为迭代实际就是通过调用next方法来实现的
next() {
if (count <= limit) {
return {
done: false,
value: count++
}
} else {
return { done: true, value: undefined }
}
}
}
}}测试
const counter = new Counter(3)for (let i of counter) {
console.log(i)}console.log('另一轮迭代:')for (let i of counter) {
console.log(i)}
就和使用 for-of循环一样,迭代器会很聪明地去调用 next方法,当迭代器提前终止时,它也会去调用 return方法。
[Symbol.iterator]() {
let count = 1
const limit = this.limit return {
// 迭代器工厂函数必须要要返回一个带有next方法的对象,因为迭代实际就是通过调用next方法来实现的
next() {
if (count <= limit) {
return {
done: false,
value: count++
}
} else {
return { done: true, value: undefined }
}
},
return() {
console.log('提前终止迭代器')
return { done: true }
}
}}测试
const counter = new Counter(5)for (let i of counter) {
if (i === 3) {
break;
}
console.log(i)}
如果迭代器没有关闭,就可以继续从上次离开的地方继续迭代。数组地迭代器就是不能关闭的。
const arr = [1, 2, 3, 4, 5]const iter = arr[Symbol.iterator]()iter.return = function () {
console.log('提前退出迭代器')
return {
done: true
}}for (const i of iter) {
console.log(i)
if (i === 2) {
break
}}for (const i of iter) {
console.log(i)}
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇文章我们来了解TypeScript的函数重载功能的相关内容,主要介绍TypeScript中函数重载写法,下文有很详细的介绍,对大家学习或工作会有帮助,接下来就跟随小编来一起学习一下吧!
这篇文章主要介绍了Vue3 使用axios拦截器打印前端日志,这是一种比较值得推荐的方式,也就是写一次,就不用总写console.log了。下面来看看文章的详细内容,需要的朋友可以参考一下
在网页设计中,导航栏的设计也是很重要的一部分,但是网上很多导航栏都是千篇一律的,对此这篇文章就给大家分享一个动画导航栏效果的实现,实现代码及效果如下,感兴趣的朋友可以参考。
原型是function对象下的属性,它定义了构造函数的共同祖先,也就是一个父子级的关系,子对象会继承父对象的方法和属性,每个实例对象下都有__proto__属性,通过属性__proto__指向构造函数的原型对象,当到达末端时,返回null,这样一层一层向顶端查找,就形成了原型链
Object.create与new的原理怎样理解,两者不同在哪?有不少朋友对此感兴趣,下面小编给大家整理和分享了相关知识和资料,易于大家学习和理解,有需要的朋友可以借鉴参考,下面我们一起来了解一下吧。
成为群英会员,开启智能安全云计算之旅
立即注册关注或联系群英网络
7x24小时售前:400-678-4567
7x24小时售后:0668-2555666
24小时QQ客服
群英微信公众号
CNNIC域名投诉举报处理平台
服务电话:010-58813000
服务邮箱:service@cnnic.cn
投诉与建议:0668-2555555
Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 ICP核准(ICP备案)粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008