文章目录
什么是迭代器模式
迭代器(iterator)有时又称光标(cursor)是程序设计的软件设计模式,可在容器对象(container,例如链表或数组)上遍访的接口,设计人员无需关心容器对象的内存分配的实现细节。 —百度百科
一个比方:电视机的频道当成一个数据集合,遥控器就相当于一个迭代器
迭代器模式
分离了集合对象的遍历行为,抽象出一个迭代器来负责,我无需知道内部的数据结构,又可以让外部透明的进行访问
为什么js要产生迭代器
ES6之前
上面不同的数据结构都要使用不同的遍历方法,否则会报语法错位,这样不利于简化编程,所以产生了一种方式来统一遍历方式
ES6的迭代器
const items = ['first','second','third']
const it = items[Symbol.iterator]() //调用了ES6的迭代器方法 it成为了一个迭代器
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
调用迭代器之后会产生下面对象,有两个属性,其中done为true时表示不可以遍历了,数据遍历完了
自定义迭代器
用迭代器模式
写一个和上面一样的迭代器方法
class Iterator {
constructor(list) {
this.list = list
this.index = 0;
}
// 相当于上面迭代器的next()方法
next() {
if (this.hasNext()) {
return {
value: this.list[this.index++],
done: false
}
}else{
return{
value: undefined,
done: true
}
}
}
hasNext() {
if (this.list.length > this.index) {
return true
} else {
return false
}
}
}
// 获取迭代器
class Factory {
constructor(list) {
this.list = list
}
// 获取迭代器 相当于上面ES6的 [Symbol.iterator]() 方法
// 面向对象思想写法 写这个Factory的作用
getIteractor() {
return new Iterator(this.list)
}
}
效果相同
let arr = [9, 8, 7]
let model = new Factory(arr)
let iterator = model.getIteractor()
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
getIteractor() 方法,获取迭代器 相当于上面ES6的 Symbol.iterator 方法,写这个Factory的作用,面向对象思想写法
Iterator的概念
遍历器(Iterator)它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作
(即依次处理该数据结构的所有成员, 之前只有数组和NodeList等比较特殊的类数组才拥有该特性)
Iterator的三个作用
- 一是为各种数据结构,提供一个统一的、简便的访问接口;
- 二是使得数据结构的成员能够按某种次序排列
- 三是 ES6 创造了一种新的遍历命令for…of循环,Iterator 接口主要供for…of消费
Iterator的实现步骤
- 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象
- 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员
- 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
- 不断调用指针对象的next方法,直到它指向数据结构的结束位置
每一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。
以我的理解:学过数据结构的人会将其类比为链式存储结构
Iterator的实现原理
由于 Iterator 只是把接口规格加到数据结构之上,所以,遍历器与它所遍历的那个数据结构,实际上是分开的,完全可以写出没有对应数据结构的遍历器对象,或者说用遍历器对象模拟出数据结构。
默认的迭代器(Iterator)接口
ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)
一种数据结构只要部署了 Iterator 接口,我们就称这种数据结构是“可遍历的”(iterable)。
Iterator 接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for…of循环(。当使用for…of循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。
原生具备 Iterator 接口的数据结构如下。
- Array
- Map
- String
- TypedArray(个底层二进制数据缓存区的类数组)
- Sett
- NodeList 对象
for… …of循环与迭代器的关系
数组原生具备iterator接口(即默认部署了Symbol.iterator属性),for…of循环本质上就是调用这个接口产生的遍历器,可以用下面的代码证明。
const week = ['Monday','Tuesday','Wednesday']
for(let v of week){
console.log(v);
}
const obj = {}
obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr)
for(let v of obj){
console.log(v);
}
上侧代码中,空对象obj部署了数组arr的Symbol.iterator属性,结果obj的for…of循环,产生了与arr完全一样的结果。