迭代器详解

92 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情

前言

之前对生成器,迭代器学的比较模糊,最近开始重新复习了一下,学习的总结内容在这分享给大家,欢迎相互学习,共同进步!

一. 什么是迭代器?

迭代器是确保用户可以在容器对象(如链表、数组)上访问对象,不需要关注对象内部实现。简单来说其就是帮助我们对某个数据结构进行遍历的对象。迭代器迭代器是一个具体的对象,这个对象需要符合迭代器协议(iterator protocol),即定义了产生一系列值的标准方式,在js中用next方法

next方法:一个无参数或者一个参数的函数,返回一个必须拥有两个属性对象:done(boolean)和value。

举例:

const names = ["hh", "kk", "oo"]

// 创建一个迭代器对象来访问数组
let index = 0
const Iterator = {
  next: function() {
    if (index < names.length) {
      return { done: false, value: names[index++] }
    } else {
      return { done: true, value: undefined }//可省略,不能迭代后默认返回undefined
    }
  }
}

console.log(Iterator.next())
console.log(Iterator.next())
console.log(Iterator.next())
console.log(Iterator.next())
console.log(Iterator.next())

image.png

由上可知:迭代器如果迭代完毕,done为true,value为undefined,当然其可省略,省略的话就是返回undefined

1. 迭代器函数

我们可以创建迭代器函数,传入可迭代的数组进行迭代,当然可以创建无限的迭代器。

举例:

function createArrayIterator(arr) {
  let index = 0
  return {
    next: function() {
      if (index < arr.length) {
        return { done: false, value: arr[index++] }
      } else {
        return { done: true, value: undefined } 
      }
    }
  }
}
const nums = [10, 22, 33, 12]

const numsIterator = createArrayIterator(nums)
console.log(numsIterator.next())
console.log(numsIterator.next())
console.log(numsIterator.next())
console.log(numsIterator.next())

//一个无限的迭代器
function createNumberIterator() {
  let index = 0
  return {
    next: function() {
      return { done: false, value: index++ }
    }
  }
}

2.可迭代对象

一个对象满足可迭代,就必须实现可迭代的方法,在代码中我们使用Symbol.iterator访问属性。

举例:

// 创建一个iterableObj迭代器对象来访问数组
const iterableObj = {
  names: ["hh", "kk", "oo"],
  [Symbol.iterator]: function() {
    let index = 0
    return {
      next: () => {
        if (index < this.names.length) {
          return { done: false, value: this.names[index++] }
        } else {
          return { done: true, value: undefined }
        }
      }
    }
  }
}

const iterator = iterableObj[Symbol.iterator]()
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())

通常我们for.. of遍历的对象就是可迭代对象。js中内置的迭代对象有:Stirng、Array、Map、Set、arguments对象、NodeList集合。

举例:

const names = ["abc", "cba", "nba"]
console.log(names[Symbol.iterator]) // [Function: values]

// const iterator1 = names[Symbol.iterator]()
// console.log(iterator1.next())
// console.log(iterator1.next())
// console.log(iterator1.next())
// console.log(iterator1.next())

for (const item of names) {
  console.log(item)
}

// Map/Set
const set = new Set()
set.add(10)
set.add(100)
set.add(1000)

console.log(set[Symbol.iterator])//[Function: values]

for (const item of set) {
  console.log(item)
}

// 函数中arguments也是一个可迭代对象
function foo(x, y, z) {
  console.log(arguments[Symbol.iterator]) //[Function: values]
  for (const arg of arguments) {
    console.log(arg)
  }
}

foo(10, 20, 30)

可迭代对象应用于:

  1. JavaScript中语法:for ...of、展开语法、yield*(生成器)、解构赋值;
  2. 创建一些对象:new Map([Iterable])、new WeakMap([iterable])、new Set([iterable])、new WeakSet([iterable]);
  3. 一些方法的调用:Promise.all(iterable)、Promise.race(iterable)、Array.from(iterable);

举例:

names=[1,23,33]
//展开运算符
const newNames = [...names, ...iterableObj]

//解构语法
const [ name1, name2 ] = names

// 一些对象
const set1 = new Set(iterableObj)
const set2 = new Set(names)

const arr1 = Array.from(iterableObj)

// Promise.all
Promise.all(iterableObj).then(res => {
  console.log(res)
})

三. 自定义类迭代器

上方我们知道Array、Set、String、Map等类创建出来的对象是可迭代对象,然而我们也可以自己自定义一个类,让其创建的对象都是可迭代的。

举例:

class Classroom {
  constructor(address, name, students) {
    this.address = address
    this.name = name
    this.students = students
  }

  add(newStudent) {
    this.students.push(newStudent)
  }

  [Symbol.iterator]() {
    let index = 0
    return {
      next: () => {
        if (index < this.students.length) {
          return { done: false, value: this.students[index++] }
        } else {
          return { done: true, value: undefined }
        }
      },
      //return 方法可以终止迭代
      return: () => {
        console.log("迭代器终止了~")
        return { done: true, value: undefined }
      }
    }
  }
}

const classroom = new Classroom("中山路", "前端", ["james", "kobe"])
classroom.add("lilei")

for (const stu of classroom) {
  console.log(stu)
  // if (stu === "kobe") break // 也可以break 终止迭代
 }

总结

学完这个大家可点击该链接,学习一些生成器一种特殊的迭代器。