目录
前言
概念
优点
用法
对象迭代能力
为什么对象没有迭代器
迭代器的实现
生成器
基础语法
生成器传参
生成器委托
可终止迭代器
总结
前言
在ES6中引入了迭代器的概念,它是一种遍历数据集合的机制,提供了一种简单而一致的方式来访问集合中的每个元素,在集合与映射这篇文章中,我们就已经初步认识了Symbol.iterator这个概念。
概念
迭代器是通过迭代协议实现的,每一个拥有该协议的对象都可以称作是可迭代的对象,这个协议的标识就是Symbol.iterator,它是ES6中引入的一个新的Symbol值,表示一个对象是否有可迭代性。可迭代对象的Symbol.iterator属性是一个函数,我们称为迭代器对象,运行这个函数会返回一个next函数(next函数可以当成是JS的原型链或者C中链表的指针),运行next函数后又可以接收两个属性:value和done;value表示当前迭代的值;done表示遍历完全部迭代。
在JS中可迭代的对象有以下几种:
- Array(数组)
- Map(映射)
- Set(集合)
- String(字符串)
- TypedArray(类数组)
- NodeLists(Dom节点)
需要注意的是Object没有迭代能力
优点
-
灵活性:迭代器提供了一套灵活的遍历机制,使用相同的语法和操作方式于不同类型的数据结构
-
可迭代性:通过实现迭代器协议,可以让对象具有可迭代性,从而可以使用for of循环来遍历对象,增强代码可读性
-
惰性求值:迭代器是一种惰性求值的机制,只有在需要下一个元素时才会取值,这样可以节省内存,提高性能
-
可中断性:迭代器可以在任意时刻中断遍历,而不需要遍历整个数据结构,提高代码的效率
-
支持函数式编程:迭代器是函数式编程中常用的工具,它可以和其他函数式编程的特性一起使用,例如高阶函数、map、filter、reduce 等等
用法
简单介绍一下迭代器的用法,使用[Symbol.iterator]()运行迭代对象,获取next,运行next获取迭代值
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(arr[Symbol.iterator]().next()); // { value: 1, done: false }
我们可以借助while对数组执行遍历操作
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
const iterator = arr[Symbol.iterator]()
let next
while (next = iterator.next(), !next.done) {
console.log(next.value); // 1~9
}
或者通过ES6新增的for of对迭代对象进行遍历,for of和for in类似,for in是遍历索引,for of是遍历属性值
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for (const iterator of arr) {
console.log(iterator);
}
对象迭代能力
为什么对象没有迭代器
对象是一种无序的集合类型,与数组或类数组不同,它的属性名称是字符串或Symbol类型,并且不具备索引。因此对象不能像数组一样使用简单的循环结构来遍历属性值,而是需要通过一些特殊的方法来实现对象的迭代。
迭代器的实现
基于上面的用法,我们可以尝试在对象上实现迭代器
Reflect.defineProperty(Object.prototype, Symbol.iterator, {
value: function () {
const keys = Reflect.ownKeys(this).filter(it => it !== Symbol.iterator) // 过滤自身
const len = keys.length
let count = 0
return {
next: () => ({ value: this[keys[count++]], done: count > len })
}
}
})
可以看到,对象像迭代对象一样也可以通过迭代的方式获取到值
const obj: any = {
name: "阿黄",
age: 10,
like: "meat"
}
const iterator = obj[Symbol.iterator]()
let next
while (next = iterator.next(), !next.done) {
console.log(next.value); // 阿黄 10 meat
}
for (const iterator of obj) {
console.log(iterator); // 阿黄 10 meat
}
生成器
生成器(Generator)是 ES6 中新增的一种特殊函数,它的语法与迭代器有共同之处,可以看作是一种特殊的迭代器,它通过function*关键字来定义。生成器函数的内部可以使用yield关键字来暂停函数的执行,并返回执行结果,同时也可以再次从暂停的位置开始执行。在函数外部使用next()函数来获取生成器的迭代值,结构与上面的迭代器相同,包含value和done值
基础语法
比如,我们使用一个数组来表示函数异步的内容,在内部使用yield对函数进行暂停操作,在外部使用generator.next()对内部暂停的结果取迭代值
function* start(list: any[]) {
let i = list.length
while (i-- >= 0) {
yield list[i]
}
}
const arr = [1, 2, 3, 4, 5]
const generator = start(arr)
let next
while (next = generator.next(), !next.done) {
console.log(next.value); // 5~1
}
生成器传参
在next函数中传入参数可以将参数带入生成器函数中,比如
function* start(q1: string) {
const name: string = yield q1
yield `我叫${name}`
}
const generator = start("你叫什么名字")
console.log(generator.next().value);// 你叫什么名字
console.log(generator.next("张三").value);// 我叫张三
生成器委托
生成器之间可以使用yield*关键字进行传递,函数中的多个生成器会连接在一起,一起输出值
function* getName(name: string) {
yield `我叫`
yield `${name}`
}
function* getAge(age: number) {
yield `我${age}了`
}
function* getInfo(__name: string, __age: number) {
yield* getName(__name)
yield* getAge(__age)
}
const generator = getInfo("张三", 20)
console.log(generator.next().value);// 我叫
console.log(generator.next().value);// 张三
console.log(generator.next().value);// 我20了
上面的getInfo等同于
function* getInfo(__name: string, __age: number) {
yield `我叫`
yield `${__name}`
yield `我${__age}了`
}
可终止迭代器
可终止迭代器在ES6中并未正式加入,但是却有相关的声明,使用return函数可以跳出迭代。使用throw函数可以跳出迭代并抛错,所以我们可以借助上面的对象迭代器的方式,实现一个迭代终止的功能
首先我们实现一个数组的迭代器,数组和对象区别在于已经存在length属性,所以我们做个兼容就行了
Reflect.defineProperty(Array.prototype, Symbol.iterator, {
value: function () {
const keys = Reflect.ownKeys(this).filter(it => it !== Symbol.iterator) // 过滤自身
const len = this.length ?? keys.length
let count = 0
return {
next: () => {
const done = count >= len
return { value: !done ? this[keys[count++]] : void 0, done }
},
}
}
})
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
const iterator = arr[Symbol.iterator]()
let next
while (next = iterator.next(), !next.done) {
console.log(next.value); // 1~9
}
然后我们在迭代器中增加return函数和throw函数
throw(err?: string) {
throw new Error(err)
},
return() {
count = len
return { done: true };
}
接着在数组中使用一下
return函数:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
const iterator: any = arr[Symbol.iterator]()
console.log(iterator.next());// { value: 1, done: false }
iterator.return()
console.log(iterator.next());// { value: undefined, done: true }
throw函数:
console.log(iterator.next());// { value: 1, done: false }
iterator.throw("抛个错")// Error: 抛个错
总结
本文介绍了JS迭代器的概念以及用法,并使用反射机制在Object中实现了迭代器,此外,生成器是特殊的迭代器,它的使用与迭代器类似,最后实现了迭代器中的可终止迭代器,使迭代器拥有终断功能文章来源:https://www.toymoban.com/news/detail-563614.html
以上就是全部内容了,感谢你的阅读,如果觉得文章不错的话,还望支持一下博主,谢谢~文章来源地址https://www.toymoban.com/news/detail-563614.html
到了这里,关于JS的迭代器是啥?精读JS迭代器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!