迭代器iterator
1.1. 什么是迭代器,创建迭代器
- 迭代器本身其实就是一个对象
- 要想创建迭代器,就需要这个对象中有一个next方法,并且next方法会返回一个对象,对象中有done和value属性
- 如果还有数据没有遍历完,done的值就是
false,否则为true
- 如果还有数据没有遍历完,done的值就是
- 返回{done: false/true, value: value/undefined}
const arrs = ["abc", "cba", "nba"]
const friends = ["kobe", "james", "linda", "Judy"]
function createIterator(arr) {
let index = 0
// 迭代器
return {
next: function() {
if(index < arr.length) {
return { done: false, value: arr[index++] }
} else {
return { done: true }
}
}
}
}
const iterator1 = createIterator(arrs)
console.log(iterator1.next())
console.log(iterator1.next())
console.log(iterator1.next())
console.log(iterator1.next())
const iterator2 = createIterator(friends)
console.log(iterator2.next())
console.log(iterator2.next())
console.log(iterator2.next())
console.log(iterator2.next())
console.log(iterator2.next())
1.2. 什么是可迭代对象
- 当一个对象实现了**可迭代协议(iterator protocol)**时,它就是一个可迭代对象
- 意思就是这个对象中必须实现@iterator方法,也就是在代码中写的**[Symbol.interator]**方法
- [Symbol.interator]方法必须返回一个迭代器
- 当一个对象称为可迭代对象之后,就可以使用比如for...of这样的操作
const obj = {
name: "Judy",
age: 18,
height: 1.88,
friends: ["kobe", "james", "coderWhy", "coderKing"],
// 想成为一个可迭代对象,就必须实现下面的方法
// 想要for...of遍历时,遍历出来什么东西,是由我说了算的
[Symbol.iterator]: function() {
let index = 0
// 此时,迭代出来的是所有的key
// const keys = Object.keys(obj)
// 此时,迭代出来的是所有的value
// const values = Object.values(obj)
// 此时,迭代出来的是我的各个朋友
// const friends = this.friends
// 此时,迭代出来的是键值对数组
const keysValues = Object.entries(obj)
return {
next: function() {
if (index < keysValues.length) {
return { done: false, value: keysValues[index++] }
} else {
return { done: true }
}
}
}
}
}
// 此时,由于obj对象已经实现了可迭代协议,所以它是可以使用for...of的
for (let item of obj) {
console.log(item)
}
1.3. 原生迭代器对象
- 事实上,平时使用的许多原生对象都已经实现了可迭代协议,因此它们可以使用for...of
- 例如:Array/String/Set/Map/NodeList(节点列表)/arguments对象
1.4. 可迭代对象的应用
-
只有可迭代对象才能使用的一些语法
-
for...of
-
展开运算符
-
yield*
-
解构赋值
-
-
创建一些对象时,要求必须传入的是可迭代对象
-
new Map(iterable)
-
new WeakMap(iterable)
-
new Set(iterable)
-
new WeakSet(iterable)
-
-
使用一些方法时,也要求必须传入的是可迭代对象
-
Array.from(iterbale)
-
Promise.all(iterable)
-
Promise.race(iterable)
-
1.5. 自定义类的迭代
-
如果希望自己创建的一个类中的对象,默认也是可以迭代的,那么就可以在创建类的时候,给它加一个实例方法[Symbol.iterator],那么这个类的实例就也可以被for...of遍历了
-
创建一个classroom类,教室有名字,地址,学生,这个教室可以进来新的学生。并且这个类是可迭代的
class Classroom {
constructor(name, address, ...students) {
this.name = name
this.address = address
this.students = students
}
newStudent(student) {
this.students.push(student)
}
// 在类中写好实例方法,那么这个类所new出来的实例对象,就都是可迭代的了
[Symbol.iterator]() {
let index = 0
let allStudents = this.students
return {
next: function() {
if (index < allStudents.length) {
return { done: false, value: allStudents[index++] }
} else {
return { done: true }
}
}
}
}
}
const Classroom1 = new Classroom("2201", "2号楼", "kobe", "james")
Classroom1.newStudent("coderWhy")
Classroom1.newStudent("linda")
const Classroom2 = new Classroom("2202", "2号楼", "李明", "王红")
Classroom2.newStudent("李强")
Classroom2.newStudent("王虎")
for(let student of Classroom1) {
console.log(student)
}
for(let student of Classroom2) {
console.log(student)
}
1.6. 监听迭代器的中断
-
迭代器有时候会因为某些原因,没有完全迭代,就终止。这个时候就可以使用return来进行监听
-
比如break或者throw就会中断迭代
class Classroom {
constructor(name, address, ...students) {
this.name = name
this.address = address
this.students = students
}
[Symbol.iterator]() {
let index = 0
let allStudents = this.students
return {
next: function() {
if (index < allStudents.length) {
return { done: false, value: allStudents[index++] }
} else {
return { done: true }
}
},
// 监听迭代中断
return: function() {
console.log("迭代中断了")
return { done: true }
}
}
}
}
const Classroom1 = new Classroom("2201", "2号楼", "kobe", "Judy")
for(let student of Classroom1) {
console.log(student)
if (student === "Judy") {
// break
throw new Error("Judy来咯")
}
}