Iterator迭代器

简要描述:

  • 一种接口机制,为各种不同的数据结构提供统一访问的机制。
  • 主要供for...of消费。
  • 一句话 :不支持遍历的数据结构“可遍历”。
    原生具备 Iterator 接口的数据结如下,可通过for...of进行遍历:
    Array、Map、Set、String、TypedArray(用于二进制数据的)、函数的arguments对象、NodeList对象
1. 模拟一个iterator执行
function makeIterator(arr) {
    let nextIndex = 0;
    return {
        next() {
            return nextIndex < arr.length ? 
              { value: arr[nextIndex++], done: false  } : { value: undefined, done: true }
        }
    }
}
let it = makeIterator(['a', 'b', 'c'])
console.log(it.next()); //{value: 'a', done: false}
console.log(it.next()); //{value: 'b', done: false}
console.log(it.next()); //{value: 'c', done: false}
console.log(it.next()); //{value: undefined, done: true}

以上是不是让你想起了Generator函数,调用方式也是通过next一次一次调,打印的数据结构也一样,Generator函数内部封装了迭代器。

2. 拿数组举例
let arr = [1, 2, 3]
for (let key of arr) {
    console.log(key)
}
console.log(Symbol.iterator) //Symbol(Symbol.iterator)
let ite = arr[Symbol.iterator](); 
console.log(ite) //Array Iterator {}
console.log(ite.next()) //{value: 1, done: false}
console.log(ite.next()) //{value: 2, done: false}
console.log(ite.next()) //{value: 3, done: false}
console.log(ite.next()) //{value: undefined, done: true}

控制台中打印arr,展开[[prototype]],发现有个Symbol(Symbol.iterator)属性,这个就是它的迭代器,就是数组能用for...of遍历的原因


image.png

想要数据能够用for...of进行遍历,就要给数据提供Iterator迭代器。

3. 为数据自定义迭代器

迭代器的条件

  • 可迭代协议:当前对象是否有 Symbol.iterator 属性
  • 迭代器协议:当前迭代器必须符合条件
return {
   next() {
       return { value: ... , done: ... }
   }
}

接下来,让我们为下面的courses自制迭代器 ,让courses能够用for...of遍历到每一个数组内的元素

let courses = {
    allCources: {
        frontend: ['ES', '小程序', 'Vue', 'React'],
        backend: ['Java', 'Python'],
        webapp: ['Android', 'IOS']
    }
}
courses[Symbol.iterator] = function () { //定义Symbol(Symbol.iterator)属性,值为iterator函数
    let allCources = this.allCources;
    let keys = Reflect.ownKeys(allCources) //取到数组的属性名,包括Symbol
    let values = [];//所有元素放到这里
    return {
        next() {
            if (!values.length) {
                if (keys.length) { //没有
                    // 往values里添加数据,确保每次的next调用,都能return出values中的值
                    values = allCources[keys[0]]; //keys每次从0开始取,取过的就shift删掉,避免取重复的
                    keys.shift();
                }
            }
            return {
                done: !values.length, //values要是空了,代表都取过了,返回true
                value: values.shift() //return出values中的值
            }
        }
    }
}
for (let key of courses) {
    console.log(key)
}
// 打印结果:ES 小程序 Vue React Java Python Android IOS
4. 异步迭代器
  • Symbol.asyncIterator
  • for await (...of...)
function getPromise(time) { //异步函数
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve({ value: time, done: false }) //next返回值
        }, time)
    })
}
let arr = [getPromise(1000), getPromise(2000), getPromise(3000)];//要被遍历的数组,数组元素都是异步函数

arr[Symbol.asyncIterator] = function () { //异步迭代器
    let nextIndex = 0;
    return {
        next() { //返回值为 在同步的返回值写法上包裹一层promise
            return nextIndex < arr.length ? arr[nextIndex++] : Promise.resolve({ value: undefined, done: true })
        }
    }
}
async function test(){
    //for await(... of ...)等到当前元素完成再遍历下一个元素,并且遍历到的是异步完成的结果值
    for await (let item of arr){ //遍历到异步的结果
        console.log(item) //1000 2000 3000
    }
}
test(); //调用异步函数

你可能感兴趣的:(Iterator迭代器)