Iterator(遍历器)概念
-
Iterator目的
- 为各种数据结构,提供统一的访问机制
- 使数据结构成员,按照某种次序排列
- 提供新的遍历命令:for…of循环
-
Iterator遍历过程
- 创建指针对象,指向数据起始位置
- 调用指针对象next方法,指针指向数据第一个成员,返回{value,done}对象
- 重复步骤2,指针后移,直至数据结束位置
-
遍历器模拟
//遍历器模拟
var it = maker()
it.next() //{value: 0, done: false}
it.next() //{value: 1, done: false}
it.next() //{value: 2, done: false}
function maker() {
var index = 0
return {
next() {
return { value: index++, done: false }
}
}
}
- 自定义遍历器
//自定义遍历器:执行Symbol.iterator方法,返回遍历器对象,该对象具有next方法
class RangeIterator {
constructor(start, stop) {
this.value = start
this.stop = stop
}
[Symbol.iterator]() { return this }
next() {
let { value, stop } = this
if (value < stop) {
this.value++
return { value }
} else {
return { done: true }
}
}
}
function range(start, end) {
return new RangeIterator(start, end)
}
//单个输出
var it = range(1, 3)[Symbol.iterator]()
it.next() //{value: 1}
it.next() //{value: 2}
it.next() //{done: true}
//for...of遍历(默认调用Symbol.iterator方法,后调用next循环)
for (let v of range(0, 5)) {
console.log(v) //依次输出0-4
}
- 修改数组for…of输出
//修改数组for...of遍历,输出2倍值
var arr = [1, 2, 3]
Array.prototype[Symbol.iterator] = function () {
let me = this
let i = 0
return {
next() {
if (i++ < me.length) {
return { value: me[i - 1] * 2 }
} else {
return { done: true }
}
}
}
}
var it = arr[Symbol.iterator]()
for (let v of arr) { //谷歌浏览器:输出2,4,6
console.log(v)
}
默认Iterator接口
- 使用for…of时,自动调用Iterator接口
- 部署Iterator - “可遍历的” - Symbol.iterator属性(值为函数)
//Symbol.iterator
var obj = {
[Symbol.iterator]() {
return {
index: 1,
next() {
return {
value: this.index++,
done: false
}
}
}
}
}
//next调用
var it = obj[Symbol.iterator]()
it.next() //{value: 1, done: false}
it.next() //{value: 2, done: false}
//for...of循环: 自动调用obj的Symbol.iterator方法,并调用next遍历
for (var i of obj) {
console.log(i) //输出1-9
if (it.next().value > 10) {
break
}
}
- 原生具备Iterator数据结构(Iterator在原型上)
- Array
- Map
- Set
- String
- TypedArray
- arguments对象
- NodeList对象
//Array: 输出value,
var arr = [1, 2, 3]
for(let v of arr){
console.log(v)
}
//Map: 输出key,value
var m = new Map([['a', 1], ['b', 2]])
for (let [v, k] of m) {
console.log(k, v)
}
//Set: 输出value
var s = new Set([1, 2, 3, 1, 2, 3])
for (let v of s) {
console.log(v)
}
//String:输出每个字符串
var str = '1231'
for (let v of str) {
console.log(v)
}
//Arguments: 遍历参数
fun(1, 2, 3)
function fun() {
for (let v of arguments) {
console.log(v)
}
}
//NodeList: 输出p元素
var eles = document.getElementsByTagName('p')
for (let v of eles) {
console.log(v)
}
- 原型的Iterator
//Iterator部署在原型上
arr[Symbol.iterator] === Array.prototype[Symbol.iterator] //true
//覆盖默认Iterator
var str = '123'
String.prototype[Symbol.iterator] = () => {
return {
next() {
return { a: 1 }
}
}
}
for (let v of str) {
console.log(v)
}
- 自定义Iterator接口
- 可在原型链上部署Iterator
- Symbol.iterator方法不是遍历器生成函数,遍历则报错
//覆盖默认Iterator:字符输出为x
var str = '123'
String.prototype[Symbol.iterator] = function () {
let me = this
let i = 0
return {
/**
* 1. next必须返回对象格式
* 2. 返回done为true时,遍历结束,for...of循环退出
*/
next() {
if (i++ < me.length) {
return {
value: 'x'
}
} else {
return {
done: 1
}
}
}
}
}
for (let v of str) {
console.log(v)
}
使用场合(默认调用Symbol.iterator)
- 解构赋值
- 扩展运算符
- 扩展运算符重写
var str = 'hello';
[...str] //["h", "e", "l", "l", "o"]
//覆盖默认Iterator:字符输出为x
String.prototype[Symbol.iterator] = function () {
let me = this
let i = 0
return {) {
if (i++ < me.length) {
return {
value: 'x'
}
} else {
return {
done: 1
}
}
}
}
};
[...str] //["x", "x", "x", "x", "x"]
- yield*
//遍历生成器, yield*后面的可遍历结构会自动遍历
var generator = function* () {
yield 1
yield* '234'
yield 5
}
for (let v of generator()) { //依次输出1-5
console.log(v)
}
- 接受数组作为参数
- for…of
- Array.from()
- Map,Set…
- Promise.all…
//接受数组作为参数
Array.from([1, 2]) //[1,2]
//重写
Array.prototype[Symbol.iterator] = function* () {
yield 'hi';
};
Array.from([1, 2]) //["hi"]
new Set([1,2]) //Set(1) {"hi"}
扩展
- Iterator与Generator函数
// Iterator的简单实现: Generator
var it = {
*[Symbol.iterator]() {
yield* [1, 2, 3]
}
};
//...和for...of均依次输出1,2,3
[...it]
for (let x of it) {
console.log(x)
}
- Iterator中的return/throw方法
//遍历结束(报错或break):走return
var it = {
[Symbol.iterator]() {
let i = 0
return {
next() {
if (i > 5) {
return { done: 1 }
}
return { value: i++ }
},
//必须返回对象, next返回done:true后,不走return
return() {
console.log('return')
return {}
}
}
}
};
for (let x of it) {
if (x++ > 3) break;
console.log(x) //走return
}
for (let x of it) {
if (x++ > 8) break;
console.log(x) //不走return
}
- for…of循环
- 一个数据结构只要部署了Symbol.iterator属性,就被视为具有 iterator 接口,就可以用for…of循环遍历它的成员
- 计算生成的数据结构(可遍历)
- 三个对象: Array,Set,Map
- 三个返回遍历器对象的方法:entries,keys,values
Array.prototype.entries //f
Set.prototype.entries //f
Map.prototype.entries //f
Object.prototype.keys //undefined
let map = new Map([[1, 1], [2, 2]]);
[...map.entries()] //[Array(2), Array(2)]
- 与其他遍历语法的比较
- for循环:写法麻烦
- forEach:break和return命令失效
- for…in
- 数组键名是字符串
- 不仅仅遍历数字键名
- 遍历顺序无法保证
- 为对象遍历设计,不适用于数组
- for…of无for…in的缺点,可以使用break等,为所有可遍历结构的统一接口
//for...in
var arr = [1,2,3]
Array.prototype.c = 'c'
arr.d = 'd'
arr.a = 'a'
//依次输出0,1,2,d,a,c
for(let k in arr){
console.log(k)
}
//1,2,3
for(let v of arr){
console.log(v)
}