Javascript 从迭代器获取当前值

Javascript 从迭代器获取当前值,javascript,iterator,generator,Javascript,Iterator,Generator,我在研究javascript生成器和迭代器,想知道是否有一种方法可以编写一个生成器函数来返回当前位置的值——当然不必调用next(),也不必记住上次next()调用返回的值 更具体地说,我失败的尝试: function* iterable(arr) { this.index = 0; this.arr = arr; while(this.index < this.arr.length) { yield this.arr[this.index++]; } } iter

我在研究javascript生成器和迭代器,想知道是否有一种方法可以编写一个生成器函数来返回当前位置的值——当然不必调用
next()
,也不必记住上次
next()
调用返回的值

更具体地说,我失败的尝试:

function* iterable(arr) {
  this.index = 0;
  this.arr = arr;
  while(this.index < this.arr.length) {
    yield this.arr[this.index++];
  }
}
iterable.prototype.current = function () {
  return this.arr[this.index];
}

const i = iterable([0, 1, 2]);
console.log(i.current()); // TypeError: Cannot read property 'undefined' of undefined

虽然我可以只使用类(甚至是一个普通的旧函数),但我想知道是否可以使用生成器/迭代器,或者是否有更好的选择。

为什么不使用函数from,其中返回部分由值替换,而不是具有
值和
完成属性的对象

函数生成迭代器(数组){
变量nextIndex=0,
最后价值;
返回{
下一步:函数(){
return lastValue=nextIndexconsole.log(it.next())
console.log(i.current()); // 0
这样做不是迭代器接口的一部分,也不是生成器函数提供的。您可以提供一个迭代器包装器来完成此操作,然后通过生成器函数在生成器上使用它(尽管您不需要生成器,但标准数组迭代器可以完成此操作),请参见注释:

// Get the Iterator prototype, which has no global name
const itPrototype = Object.getPrototypeOf(
    Object.getPrototypeOf([][Symbol.iterator]())
);
function currentWrapper(source) {
    // Allow source to be an iterable or an iterator
    if (Symbol.iterator in source) {
        source = source[Symbol.iterator]();
    }
    // Create our wrapper iterator
    const it = Object.create(itPrototype);
    // Remember the last value we saw from `next`
    let current = null;
    // The iterator method
    it.next = () => {
        return current = source.next();
    };
    // Our additional methods
    it.current = () => current && current.value;
    it.currentResult = () => ({...current});
    return it;
}
这具有可重用和通用性的优点,不受特定iterable的限制

实例:

//获取迭代器原型,它没有全局名称
const itPrototype=Object.getPrototypeOf(
Object.getPrototypeOf([[Symbol.iterator]())
);
函数currentWrapper(源){
//允许源为iterable或迭代器
if(源代码中的Symbol.iterator){
source=source[Symbol.iterator]();
}
//创建我们的包装迭代器
const it=Object.create(itPrototype);
//还记得我们在“下一步”中看到的最后一个值吗`
让电流=零;
//迭代器方法
it.next=()=>{
返回电流=source.next();
};
//我们的附加方法
it.current=()=>current&¤t.value;
it.currentResult=()=>({…current});
归还它;
}
//迭代的东西
常数a=[1,2,3];
//示例用法#1:使用“当前”`
const it=currentWrapper(一个[Symbol.iterator]());
console.log(“当前”,it.current());//未定义
console.log(“next”,it.next());//{值:1,完成:false}
console.log(“当前”,it.current());//1.
console.log(“currentResult”,it.currentResult());//{值:1,完成:false}
//示例用法#2:只是迭代器的正常使用
for(currentWrapper的常量值(a)){
console.log(值);
}
。作为控制台包装器{
最大高度:100%!重要;

}
生成器函数的问题在于a)当您调用它时,它不会开始运行,它只是创建生成器(
this.arr
this.index
直到第一次调用
next()
)和b)无法从函数内部访问生成器对象,就像您使用
this
尝试的那样

相反,你会想要

function iterable(arr) {
  const gen = Object.assign(function* () {
    while (gen.index < gen.arr.length) {
      yield gen.arr[gen.index++];
    }
  }(), {
    arr,
    index: 0,
    current() {
      return gen.arr[gen.index];
    },
  });
  return gen;
}
函数可调(arr){
const gen=Object.assign(函数*(){
while(gen.index
或者,您也可以直接实现迭代器接口,而不是使用生成器语法:

function iterable(arr) {
  return {
    arr,
    index: 0,
    current() { return this.arr[this.index]; },
    next() {
      const done = !(this.index < this.arr.length);
      return { done, value: done ? undefined : this.arr[this.index++] };
    },
    [Symbol.iterator]() { return this; },
  };
}
函数可调(arr){
返回{
啊,,
索引:0,
current(){返回this.arr[this.index];},
下一个(){
const done=!(this.index

(当然,你也可以将其作为
类编写)

我认为目标是拥有一个迭代器,该迭代器具有一个附加功能(访问当前[上次检索的])值。可能吧,但会有很多开销。我不确定如何使用函数,但
const x=iterable([1,2,3]);x、 next()
生成一个
TypeError:x。对于第一个示例,next()不是函数。第二个示例在第一个
.next()
调用中返回
{done:true,value:undefined}
。@phippu Oops,感谢您的测试。你说得对,第一个问题没有真正意义,我已经换了一个更好的解决方案。
function iterable(arr) {
  return {
    arr,
    index: 0,
    current() { return this.arr[this.index]; },
    next() {
      const done = !(this.index < this.arr.length);
      return { done, value: done ? undefined : this.arr[this.index++] };
    },
    [Symbol.iterator]() { return this; },
  };
}