迭代器
遍历器
现在很多语言中都存在 Iterator 遍历器(迭代器),目的是为了是用统一接口处理不同数据类型。在 JS 中包括 Array/Object/Set/Map
等多种集合数据结构,迭代器就是为了采用统一的方式遍历数据。
常用的解构与扩展运算符内部也在使用遍历器实现。
解决的问题
以往遍历数据时比如使用 for
需要变量来记录每次迭代数据的位置,如果遍历多层需要设置多个变量用于记录并不方便。
原始实现
下面使用以往掌握的知识实现生成器,有助于更好的理解生成器。
javascript
function generator(arr) {
let i = 0;
return {
next() {
let done = arr.length <= i;
return {
value: done ? undefined : arr[i++],
done: done
};
}
};
}
let gen = new generator([1, 2, 3]);
console.log(gen.next()); //{value: 1, done: false}
console.log(gen.next()); //{value: 2, done: false}
console.log(gen.next()); //{value: 3, done: false}
console.log(gen.next()); //{value: undefined, done: false}
原理分析
默认情况下对象是不可以迭代的,当添加[Symbol.iterator]
生成器后,就会变为可迭代对象。
javascript
let object = {
data: [],
*[Symbol.iterator]() {
for (const iterator of this.data) {
yield iterator;
}
},
push(item) {
this.data.push(item);
}
};
object.push("2");
object.push("1");
for (const iterator of object) {
console.log(iterator);
}
数据结构本身或在原型链上包含 Symbol.iterator
遍历器生成方法时即为可迭代对象。Symbol.iterator
返回next
方法。
javascript
let obj = {
data: [1, 2, 3, 4],
pos: 0,
[Symbol.iterator]() {
self = this;
return {
next() {
let value = self.data[self.pos];
let done = ++self.pos > self.data.length;
return { value, done };
}
};
}
};
// let iterator = obj[Symbol.iterator]();
// console.log(iterator.next());
for (const iterator of obj) {
console.log(iterator);
}
如果对象是数字键并包含length
可以直接引用数组迭代器
javascript
let object = {
0: "1",
1: "2",
2: "3",
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (const iterator of object) {
console.log(iterator);
}
带终止的迭代器
js
// 案例: 创建一个教室类, 创建出来的对象都是可迭代对象
class Classroom {
constructor( students) {
this.students = students
}
entry(newStudent) {
this.students.push(newStudent)
}
// 实现迭代器
[Symbol.iterator]() {
let index = 0
return {
next: () => {
if (index < this.students.length) {
return { done: false, value: this.students[index++] }
} else {
return { done: true, value: undefined }
}
},
return: () => { //监听迭代器停止
console.log("迭代器提前终止了~")
return { done: true, value: undefined }
}
}
}
}
const classroom = new Classroom( ["学生1", "学生2", "学生3", "学生4", "学生5"])
classroom.entry("lilei")
for (const stu of classroom) {
console.log(stu)
if (stu === "学生4") break
}
// 打印
// 学生1
// 学生2
// 学生3
// 学生4
// 迭代器提前终止了~
系统内置的 Array/Set/String/Map/NodeList
对象都已经内置了迭代器,下面是体验数组迭代器的使用。
javascript
let arr = [1, 2, "4", "6"];
const iterator = arr[Symbol.iterator]();
console.log(iterator.next());
字符串同样实现了遍历器
javascript
let hd = "love";
let iterator = hd[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
再来看看 set 类型同样实现了遍历器
javascript
let hd = new Set().add("2").add("3");
let f = hd[Symbol.iterator]();
console.log(f.next());
解构与扩展
常用的解构与扩展运算符内部也在使用遍历器实现。
数组扩展调用遍历器
javascript
let arr = ["2", "3"];
console.log([1, 2, 3, ...arr]);
解构内部也是使用遍历器
javascript
let hd = new Set().add("3").add("4");
[a, b] = hd;
console.log(a, b); //3 4
for/of
拥有迭代特性即包含 Symbol.iterator
方法的数据结构,就可以使用for/of
遍历操作。