为什么Javascript`iterator.next()`返回一个对象?

时间:2018-12-22 09:52:16

标签: javascript performance memory-management ecmascript-6 iterable

帮助!在C#中编程了一段时间之后,我开始学习热爱Javascript,但是我仍然坚持学习热爱可迭代的协议!

为什么Javascript采用protocol并要求为每次迭代创建一个新对象?为什么next()返回具有属性donevalue的新对象,而不是采用像C#IEnumerableIEnumerator这样的协议,该协议不分配对象就以需要两次调用(一次调用moveNext以查看迭代是否完成,第二次调用current以获取值)?

是否存在一些幕后优化,这些优化跳过了next()返回的对象的分配?很难想象给定该可迭代对象不知道该对象一旦返回将如何使用...

生成器似乎没有重复使用下一个对象,如下所示:

function* generator() {
  yield 0;
  yield 1;
}

var iterator = generator();
var result0 = iterator.next();
var result1 = iterator.next();

console.log(result0.value) // 0
console.log(result1.value) // 1

嗯,here's是个线索(感谢Bergi!):

  

稍后(在3.2节中)我们将回答一个重要问题:为什么迭代器(可选)可以在最后一个元素之后返回一个值?这种功能是包装元素的原因。否则,迭代器可以简单地在最后一个元素之后返回一个公共定义的哨兵(停止值)。

在Sect中。 3.2他们讨论使用Using generators as lightweight threads。似乎说从next返回对象的原因是,即使valuedone时也可以返回true!哇此外,除了returnyield的值外,生成器还可以yield*个值,并且{{1}时return生成的值最终会像value中那样}}是done

所有这些都允许使用伪线程。伪线程这一功能值得在循环中每次分配一个新对象。总是这么出乎意料!


尽管,现在我考虑了一下,允许true“返回”一个值以启用伪线程仍然不能证明返回对象是合理的。 yield*协议可以扩展为在IEnumerator返回moveNext()之后返回对象–只需添加属性false即可在迭代完成后测试{{1} }表示hasCurrent具有有效值...

并且编译器优化是不平凡的。这将导致迭代器的性能出现很大的差异……这不会给库实现者带来问题吗?

在友好的SO社区发现的this thread中提出了所有这些观点。但是,这些争论似乎并没有持续。


但是,无论是否返回对象,在“完成”迭代之后,没人会检查值,对吗?例如。大多数人都认为以下内容会记录迭代器返回的所有值:

true

除了不是因为currentfunction logIteratorValues(iterator) { var next; while(next = iterator.next(), !next.done) console.log(next.value) } 之外,迭代器可能仍然返回了另一个值。考虑:

done

在“完成”之后返回值的迭代器是否真的是迭代器?一只手拍手的声音是什么?似乎很奇怪...


here深入介绍了我喜欢的生成器。与迭代集合的成员相反,花费大量的时间来控制应用程序的流程。


另一个可能的解释是IEnumerable / IEnumerator需要两个接口和三个方法,而JS社区更喜欢单个方法的简单性。这样,他们就不必引入符号方法(又称为接口)组的概念了……

2 个答案:

答案 0 :(得分:8)

  

是否存在一些幕后优化,这些优化跳过了next()返回的对象的分配?

是的。这些迭代器结果对象很小,通常是短命的。特别是在for … of循环中,编译器可以进行简单的转义分析,以查看该对象根本不面向用户代码(而仅面向内部循环评估代码)。垃圾收集器可以非常有效地处理它们,甚至可以直接在堆栈上分配它们。

以下是一些来源:

答案 1 :(得分:0)

Bergi已经回答了,我已经投票赞成,我只想添加这个:

您为什么还要担心返回新对象?看起来像:

{done: boolean, value: any}

您知道,无论如何您都将使用value,所以这不会占用内存。还剩什么? done: boolean很小(4个字节?),您不必担心。另外,对象指针大约为100个字节左右(我不太清楚,但是您必须同意它很小)。

此外,JS操作了数百万个对象,并对其进行分配和垃圾回收等。

P.S。此外,Felix Kling在OP下的注释中假设迭代器每次都可以返回相同的对象,但是具有可变的属性(spec并不表示每次都返回新的对象)。