Iterator迭代器
它的作用一共有三个:
- 第一是为各种数据结构,提供一个统一的、简便的访问接口
- 第二使得数据结构的成员能够按某种次序排列
- 第三ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of循环
1.Iterator原理解释
2.给对象添加iterator
一、iterator原理解释
我们先简单写一个数组,然后通过for of 遍历
let arr = ["aaa","bbb","ccc"];
for(let i of arr){
console.log(i)
}
console.log(arr)
我们点开这个数组的原型,就会发现其中包含了一个名为 Symbol.iterator的方法
我们尝试打印这个方法,会发现其中包含一个next()方法,在试着调用next(),这个时候我们就发现了,iterator其实是一个类似于单链表的数据结构,一层一层往下指,从而实现了遍历
let arr = ["aaa","bbb","ccc"];
for(let i of arr){
console.log(i)
}
console.log(arr)
let iter = arr[Symbol.iterator]()
console.log(iter)
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
所以我们可以认为,像数组一样原型内置Symbol.iterator属性的,就认为是可以for of遍历的,没有这个属性的,我们添加上这个属性,那么它就可以实现for of遍历。
以下是原生默认具备iterator接口的数据结构
- Array
- Set
- Map
- String
- arguments对象
- NodeList对象
拿字符串测试以下是否具有iterator接口
let arr = "starry";
for(let i of arr){
console.log(i)
}
console.log(arr)
let iter = arr[Symbol.iterator]()
console.log(iter)
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
二、给对象添加iterator
先来一个没有意义的简单添加,因为对象是非线性的,所以不包含iterator迭代器,使用for of 就会报错
let obj = {
0:"aaa",
1:"bbb",
2:"ccc",
// length:3,
// [Symbol.iterator]: Array.prototype[Symbol.iterator]
}
for(let i of obj){
console.log(i) //报错
}
但是我们将注释的代码放出来,给对象一个长度属性和一个和数组一样的迭代器接口就可以成功for of了
遍历成功!但是这样的添加是没有太大意义的,有意义的情况是下面这种需要自己手写一个迭代器的对象。
let obj = {
code: 200,
name: "starry",
list: [1, 2, 3, 4]
}
for (let i of obj) { // 报错
console.log(i)
}
上面的代码,直接for of 肯定会报错,假如我们想要遍历list的内容怎么办,也许你会说,直接obj.list就可以实现遍历,但是如果obj是别人私有的库呢,list是一个私有属性呢?所以转换身份,我们作为一个JS库开发者,写了一个对象,想让别人轻松使用for of 遍历自己对象的内容,就需要自己手动写一个iterator。
let obj = {
code: 200,
name: "starry",
list: ["A", "B", "c"],
[Symbol.iterator](){
let index = 0;
return {
next:() => { // 使用箭头函数改变this指向
return {value:this.list[index++],done: index === (this.list.length+1) ? true : false}
// +1是因为迭代到C的时候index就已经是3了,不加1done为true就不会打印c了
}
}
}
}
for(let i of obj){
console.log(i)
}
let iter = obj[Symbol.iterator]()
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
这里扩展一下,只要拥有了iterator接口,使用展开运算符就可以直接拿到把迭代器里的内容变成数组,比如这里的obj
let obj = {
code: 200,
name: "starry",
list: ["A", "B", "c"],
[Symbol.iterator](){
let index = 0;
return {
next:() => {
return {value:this.list[index++],done: index === (this.list.length+1) ? true : false}
}
}
}
}
console.log(...obj) // A B c