帮助!在C#中编程了一段时间之后,我开始学习热爱Javascript,但是我仍然坚持学习热爱可迭代的协议!
为什么Javascript采用protocol并要求为每次迭代创建一个新对象?为什么next()
返回具有属性done
和value
的新对象,而不是采用像C#IEnumerable
和IEnumerator
这样的协议,该协议不分配对象就以需要两次调用(一次调用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
返回对象的原因是,即使value
为done
时也可以返回true
!哇此外,除了return
和yield
的值外,生成器还可以yield*
个值,并且{{1}时return
生成的值最终会像value
中那样}}是done
!
所有这些都允许使用伪线程。伪线程这一功能值得在循环中每次分配一个新对象。总是这么出乎意料!
尽管,现在我考虑了一下,允许true
“返回”一个值以启用伪线程仍然不能证明返回对象是合理的。 yield*
协议可以扩展为在IEnumerator
返回moveNext()
之后返回对象–只需添加属性false
即可在迭代完成后测试{{1} }表示hasCurrent
具有有效值...
并且编译器优化是不平凡的。这将导致迭代器的性能出现很大的差异……这不会给库实现者带来问题吗?
在友好的SO社区发现的this thread中提出了所有这些观点。但是,这些争论似乎并没有持续。
但是,无论是否返回对象,在“完成”迭代之后,没人会检查值,对吗?例如。大多数人都认为以下内容会记录迭代器返回的所有值:
true
除了不是因为current
是function logIteratorValues(iterator) {
var next;
while(next = iterator.next(), !next.done)
console.log(next.value)
}
之外,迭代器可能仍然返回了另一个值。考虑:
done
在“完成”之后返回值的迭代器是否真的是迭代器?一只手拍手的声音是什么?似乎很奇怪...
here深入介绍了我喜欢的生成器。与迭代集合的成员相反,花费大量的时间来控制应用程序的流程。
另一个可能的解释是IEnumerable / IEnumerator需要两个接口和三个方法,而JS社区更喜欢单个方法的简单性。这样,他们就不必引入符号方法(又称为接口)组的概念了……
答案 0 :(得分:8)
是否存在一些幕后优化,这些优化跳过了
next()
返回的对象的分配?
是的。这些迭代器结果对象很小,通常是短命的。特别是在for … of
循环中,编译器可以进行简单的转义分析,以查看该对象根本不面向用户代码(而仅面向内部循环评估代码)。垃圾收集器可以非常有效地处理它们,甚至可以直接在堆栈上分配它们。
以下是一些来源:
StopIteration
exceptions 提高迭代性能的关键是确保对循环中对
iterator.next()
的重复调用进行了优化,并且最好使用诸如store这样的高级编译器技术完全避免iterResult
的分配载荷传播,逃逸分析和骨料的标量替换。为了真正提高性能,优化编译器还应该完全消除iterator
本身的分配-iterable[Symbol.iterator]()
调用-并直接在可迭代对象的后备存储上进行操作。
答案 1 :(得分:0)
Bergi已经回答了,我已经投票赞成,我只想添加这个:
您为什么还要担心返回新对象?看起来像:
{done: boolean, value: any}
您知道,无论如何您都将使用value
,所以这不会占用内存。还剩什么? done: boolean
很小(4个字节?),您不必担心。另外,对象指针大约为100个字节左右(我不太清楚,但是您必须同意它很小)。
此外,JS操作了数百万个对象,并对其进行分配和垃圾回收等。
P.S。此外,Felix Kling在OP下的注释中假设迭代器每次都可以返回相同的对象,但是具有可变的属性(spec并不表示每次都返回新的对象)。