迭代器学习

77 阅读3分钟

迭代器学习

什么是迭代器

  • 迭代器,是用户在容器对象(container,例如链表或数组)上遍访的对象,使用该接口无需关心对象的内部实现细节。
  • 其行为像是数据库中的光标,各种编程语言都有迭代器,例如Java、Python。
  • 迭代器的作用是帮助我们对某个数据结构进行遍历的对象
在JavaScript中,迭代器是一个具体的对象,这个对象需要符合迭代器协议。
  • 迭代器协议定义了产生一系列值(无论是有限还是无限个)的标准方式;
  • 在JavaScript中这个标准就是一个特定的next方法;
next方法的要求

一个无参数或者一个参数的函数,fanUI一个拥有一下两个属性的对象:

done (boolean)

  • 如果迭代器可以先生序列中的下一个值,则为false
  • 如果迭代器已将序列迭代完毕,则为TRUE。在这种情况下,value是可选的,如果它依然存在,即为迭代结束之后的默认返回值。

value

  • 迭代器返回的任何JavaScript值。done为TRUE时可省略
const friends = ["1","2","3","4"]
let index = 0
const friendIterator = {
    next: function (){
        if (index < friends.length) {
            return {
                value: friends[index++],
                done: false
            }
        } else {
            return {
                value: undefined,
                done: true
            }
        }
    }
}
console.log(friendIterator.next()) //{ value: '1', done: false }
console.log(friendIterator.next()) //{ value: '2', done: false }
console.log(friendIterator.next()) //{ value: '3', done: false }
console.log(friendIterator.next()) //{ value: '4', done: false }
console.log(friendIterator.next()) //{ value: undefined, done: true }
const friends = ["1","2","3","4"]
let index = 0
function createArrayIterator(arr) {
    return {
        next: function (){
            if (index < arr.length) {
                return {
                    value: arr[index++],
                    done: false
                }
            } else {
                return {
                    value: undefined,
                    done: true
                }
            }
        }
    }
}
const friendIterator = createArrayIterator(friends)
console.log(friendIterator.next()) //{ value: '1', done: false }
console.log(friendIterator.next()) //{ value: '2', done: false }
console.log(friendIterator.next()) //{ value: '3', done: false }
console.log(friendIterator.next()) //{ value: '4', done: false }
console.log(friendIterator.next()) //{ value: undefined, done: true }

可迭代对象

当一个对象实现了iterable protocol协议是,它就是一个可迭代对象

这个对象的要求是必须实现 @@iterator方法,在代码中使用Symbol.iterator访问该属性;

可迭代对象的好处

  • 当一个对象变成可迭代对象的时候,他就可以进行某些迭代操作;
  • 例如 for...of操作时,其实就会调用它的 @@iterator方法

可迭代对象代码:

  const info = {
    friends: ['lisi', 'wangwu', 'zhangsan'],
    [Symbol.iterator]: function () {
        let index = 0;
        return {
            next: function () {
                if (index < this.friends.length) {
                    return {
                        value: this.friends[index++],
                        done: false
                    }
                } else {
                    return {
                        value: undefined,
                        done: true
                    }
                }
            }
        }
    }
}

原生迭代器对象

事实上我们平时创建的很多原生对象已经实现了可迭代协议,会生成一个迭代器对象的:

  • String、Array、Map、Set、arguments对象、NodeList集合;
// 数组本身是一个可迭代对象
let nums = [0, 1, 0, 3, 12]
// 获取可迭代的函数
console.log(nums[Symbol.iterator]) // console.log(nums)// 调用可迭代函数,获取到迭代器
const iterator = nums[Symbol.iterator]()
console.log(iterator.next())//{ value: 0, done: false }
console.log(iterator.next())//{ value: 1, done: false }
console.log(iterator.next())//{ value: 0, done: false }
console.log(iterator.next())//{ value: 3, done: false }
console.log(iterator.next())//{ value: 12, done: false }
console.log(iterator.next())//{ value: undefined, done: true }

可迭代对象的应用

那么这些东西可以被用在哪里呢?

  • JavaScript中语法:for ...of展开语法(spread syntax)yield* 、解构赋值 (Destructuring_assignment)
  • 创建一些对象时:new Map([Iterable])new WeakMap([iterable])new Set([iterable])new WeakSet([iterable])
  • 一些方法的调用:Promise.all(iterable)Promise.race(iterable)Array.from(iterable)

自定义类的迭代

  • 在面向对象开发中,我们可以通过class定义一个自己的类,这个类可以创建很多的对象
  • 如果我们希望自定义的类创建的对象默认是可迭代,那么在设计类的时候我们可以添加上@@iterator方法
案例
  • 教室中有自己的位置、名称、当前教室的学生;
  • 这个教室可以进来新学生
  • 创建的教室是可迭代对象
class Classroom {
    constructor(name, address, initialStudent) {
        this.name = name;
        this.address = address;
        this.students = initialStudent;
    }
    push(student) {
        this.students.push(student);
    }
    [Symbol.iterator]() {
        let index = 0
        return {
            next: () => {
                if (index < this.students.length) {
                    return {value: this.students[index++], done: false}
                } else {
                    return {value: undefined, done: true}
                }
            }
        }
    }
}
const classroom = new Classroom("三年级1班", "思源楼301室", ["小红", "小白", "小黄"])
const classroom1 = new Classroom("三年级2班", "思源楼302室", ["小蓝", "小绿", "小青"])
for (const stu of classroom1) {
    console.log(stu)
}
for (const stu of classroom) {
    console.log(stu)
}

迭代器的终端

迭代器在某些情况下会在没有完全迭代的情况下中断:
  • 比如遍历的过程中通过break、return、throw中断了循环操作;
  • 比如在解构的时候,没有解构所有值;
如果我们想要监听中断的话,我们可以添加return方法:

image-20240113100034243