如何重置迭代器?

4

我正在学习迭代器/生成器,想知道是否有一种方法可以使迭代器重新启动?比如在调用最后一个 .next() 后是否有一种方法可以使它重新开始?

function nextName() {
   const current = names.next().value
  const output = document.querySelector("output")
  if (current) { 
      output.innerText = current.name
    } 
    else { 
     // code to reset it! currently I'm just displaying text
     output.innerText = 'Nothing left'
     }
}

function nameIterator(names) {
  let nextIndex = 0;
  return {
    next: function() {
      return nextIndex < names.length ? 
        { value: names[nextIndex++], done: false } :
        { done: true }
     }
  }
}

这里有一个codepen示例,以便更清楚地了解:https://codepen.io/sammiepls/pen/romyKL?editors=1010 所以当您点击按钮时,它会调用我的迭代器,每次单击时都会显示我的名称数组中的一个名称。如何使其在最后一次单击时重置,以便返回第一个名称?
因此,显示将如下所示:
Bob
Peter Sally
Bob // 再次获取 Bob
在codepen中,我还使用生成器编写了迭代器,是否有任何方法可以在遍历完数组后将其重置回第一个位置?

你想循环吗? - Dan D.
我人生中第一次看到 "function*"... 但如果你想循环,这应该可以工作 https://codepen.io/anon/pen/QzvpRw?editors=1010。只需将 const 修改为 var,并手动编写一些代码以重置 UI。 - Victor
4个回答

5
一般来说,在JS中无法重置可迭代对象。据我所知,这是有意设计的,尽管我不知道达成该结论所使用的决策过程。

然而,在您的特定情况下,您不想重置迭代器,而是想循环遍历数组。在这种情况下,您可以使用模运算符,如下所示:

function nameIterator(names) {
  let nextIndex = 0;
  return {
    next: function() {
      nextIndex = (nextIndex + 1) % names.length;
      return { value: names[nextIndex], done: false };
    }
  }
}

啊,我明白了。所以在这种情况下,它只有可能是因为我们在调整迭代器函数,但由于它们无法被重置,我们无法改变nameGenerator的工作方式? - sammiepls

1
为了解决这个问题,在迭代器完成时,重置它的方法如下:
// code to reset it!
output.innerText = 'Nothing left'
names = nameGenerator(arr);
< p > 除非有人证明我错了,否则目前我所知道的没有重置迭代器的方法。

工作代码片段示例:

const arr = [ {name: "Bob"}, {name: "Peter"}, {name: "Sally"} ];

let names = nameGenerator(arr);


function nextName() {
   const current = names.next().value
  const output = document.getElementById("output")
   if (current) { 
      output.innerText = current.name
    } 
    else { 
    // code to reset it!
      output.innerText = 'Nothing left'
      names = nameGenerator(arr);
    }
}
  
function nameIterator(names) {
  let nextIndex = 0;
  return {
    next: function() {
      return nextIndex < names.length ? 
        { value: names[nextIndex++], done: false } :
        { done: true }
    }
  }
}

function* nameGenerator() {
  let index = 0;
  while(index < arr.length) {
    yield(arr[index++])
  }
}

 document.querySelector("button").addEventListener("click", nextName)
<button id="button">click me</button>
<p id="output"></p>


哦,是的,那正是我想要的!但不知怎么回事,我无法在 CodePen 中让这个示例工作 :/ 你只是在 else 块中添加了这个 names = nameGenerator(arr);,对吧? - sammiepls
@sammiepls 你需要将 const 命名更改为 let 命名。 - kemicofa ghost

1
如果索引大于数组索引,您可以更改索引并取余数值。
function nameIterator(names) {
    let nextIndex = 0;
    return {
        next: function() {
            nextIndex++;
            nextIndex %= name.length;
            return { value: names[nextIndex], done: false };
        }
    }
}

0
我来到这个帖子上自己寻找答案,以下是我得出的结论:

class CyclicIter {

  constructor(arr) {
      this.arr = arr
      this._at = -1
    }
    [Symbol.iterator]() {
      return {
        next: () => {
          if (this._at < this.arr.length) {
            return {
              value: this.arr[this._at++],
              done: false
            }
          } else {
            this.reset()
            return {
              done: true
            }
          }
        }
      };
    };
  reset() {
    this._at = -1
  }
};

const myArray = [1, 2, 3, 4]
const myArrayIterable = new CyclicIter(myArray)
console.log(...myArrayIterable); // can be called multiple times

这个例子可能很简单,因为我对JS非常新手。欢迎提出任何建议。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接