ES6 - 迭代器


迭代器简介

迭代器是一个对象,它允许我们一次访问一个对象的集合。

以下内置类型默认是可迭代的 -

  • 细绳
  • 大批
  • 地图

如果一个对象实现了一个键为[Symbol.iterator]的函数并返回一个迭代器,则该对象被认为是可迭代的。for...of 循环可用于迭代集合。

例子

以下示例使用for..of循环声明一个数组、对其进行标记并对其进行迭代。

<script>
   let marks = [10,20,30]
   //check iterable using for..of
   for(let m of marks){
      console.log(m);
   }
</script>

上述代码的输出如下 -

10
20
30

例子

以下示例声明一个数组、标记并检索一个迭代器对象。[ Symbol.iterator ]()可用于检索迭代器对象。迭代器的 next() 方法返回一个具有'value''done'属性的对象。'done' 是布尔值,在读取集合中的所有项目后返回 true。

<script>
   let marks = [10,20,30]
   let iter = marks[Symbol.iterator]();
   console.log(iter.next())
   console.log(iter.next())
   console.log(iter.next())
   console.log(iter.next())
</script>

上述代码的输出如下所示 -

{value: 10, done: false}
{value: 20, done: false}
{value: 30, done: false}
{value: undefined, done: true}

自定义可迭代

JavaScript 中的某些类型是可迭代的(例如数组、映射等),而其他类型则不是(例如类)。默认情况下不可迭代的 JavaScript 类型可以使用可迭代协议进行迭代。

以下示例定义了一个名为CustomerList的类,它将多个客户对象存储为数组。每个客户对象都有firstName 和lastName 属性。

要使此类可迭代,该类必须实现[Symbol.iterator]()函数。该函数返回一个迭代器对象。迭代器对象有一个函数next,它返回一个对象{value:'customer',done:true/false}

<script>
   //user defined iterable
   class CustomerList {
      constructor(customers){
         //adding customer objects to an array
         this.customers = [].concat(customers)
      }
      //implement iterator function
      [Symbol.iterator](){
         let count=0;
         let customers = this.customers
         return {
            next:function(){
            //retrieving a customer object from the array
               let customerVal = customers[count];
               count+=1;
               if(count<=customers.length){
                  return {
                     value:customerVal,
                     done:false
                  }
               }
               //return true if all customer objects are iterated
               return {done:true}
            }
         }
      }
   }
   //create customer objects
   let c1={
      firstName:'Sachin',
      lastName:'Tendulkar'
   }
   let c2={
      firstName:'Rahul',
      lastName:'Dravid'
   }
   //define a customer array and initialize it let customers=[c1,c2]
   //pass customers to the class' constructor
   let customersObj = new CustomerList(customers);
   //iterating using for..of
   for(let c of customersObj){
      console.log(c)
   }
   //iterating using the next() method
   let iter = customersObj[Symbol.iterator]();
   console.log(iter.next())
   console.log(iter.next())
   console.log(iter.next())
</script>

上述代码的输出如下 -

{firstName: "Sachin", lastName: "Tendulkar"}
{firstName: "Rahul", lastName: "Dravid"}
{
   done: false
   value: {
      firstName: "Sachin",
      lastName: "Tendulkar"
   }
}
{
   done: false
   value: {
      firstName: "Rahul",
      lastName: "Dravid"
   }
}
{done: true}

发电机

在 ES6 之前,JavaScript 中的函数遵循运行到完成模型。ES6 引入了称为 Generator 的函数,它可以中途停止,然后从停止的地方继续。

生成器在函数名称前添加星号 * 字符作为前缀,并包含一个或多个yield语句。Yield关键字返回一个迭代器对象

句法

function * generator_name() {
   yield value1
   ...
   yield valueN
}

例子

该示例定义了一个带有三个yield 语句的生成器函数getMarks。与普通函数不同,生成器函数 getMarks()在调用时不会执行该函数,而是返回一个迭代器对象,该对象可帮助您执行生成器函数内的代码。

第一次调用markIter.next()时,开头的操作将运行,并且 Yield 语句会暂停生成器的执行。对markIter.next()的后续调用将恢复生成器函数,直到下一个yield表达式。

<script>
   //define generator function
   function * getMarks(){
      console.log("Step 1")
      yield 10
      console.log("Step 2")
      yield 20
      console.log("Step 3")
      yield 30
      console.log("End of function")
   }
   //return an iterator object
      let markIter = getMarks()
   //invoke statements until first yield
      console.log(markIter.next())
   //resume execution after the last yield until second yield expression
      console.log(markIter.next())
   //resume execution after last yield until third yield expression
      console.log(markIter.next())
      console.log(markIter.next()) // iteration is completed;no value is returned
</script>

上述代码的输出如下 -

Step 1
{value: 10, done: false}
Step 2
{value: 20, done: false}
Step 3
{value: 30, done: false}
End of function
{value: undefined, done: true}

例子

以下示例通过以下方式创建偶数的无限序列

* EvenNumberGenerator 生成器函数。

我们可以使用next()或使用for of循环来迭代所有偶数,如下所示

<script>
   function * evenNumberGenerator(){
      let num = 0;
      while(true){
         num+=2
         yield num
      }
   }
   // display first two elements
   let iter = evenNumberGenerator();
   console.log(iter.next())
   console.log(iter.next())
   //using for of to iterate till 12
   for(let n of evenNumberGenerator()){
      if(n==12)break;
      console.log(n);
   }
</script>

上述代码的输出如下 -

{value: 2, done: false}
{value: 4, done: false}
2
4
6
8
10