【发布时间】:2019-05-22 12:11:07
【问题描述】:
救命!在用 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 节中):为什么迭代器(可选)可以在最后一个元素之后返回一个值?这种能力是元素被包装的原因。否则,迭代器可以简单地在最后一个元素之后返回一个公开定义的标记(停止值)。
在教派中。 3.2 他们讨论使用Using generators as lightweight threads。似乎是说从next 返回对象的原因是即使done 是true 也可以返回value!哇。此外,除了yield 和yield*-ing 值之外,生成器还可以使用return 值,当done 是true 时,return 生成的值最终与value 一样!
所有这些都允许伪线程。而这个特性,伪线程,值得为每次循环分配一个新对象...... Javascript。总是那么出人意料!
尽管现在我想了想,允许yield*“返回”一个值以启用伪线程仍然不能证明返回一个对象是合理的。 IEnumerator协议可以扩展为在moveNext()返回false之后返回一个对象——只需添加一个属性hasCurrent在迭代完成后测试true表示current有一个有效值。 ..
而且编译器的优化也很重要。这将导致迭代器的性能出现相当大的差异......这不会给库实现者带来问题吗?
所有这些观点都在友好的 SO 社区发现的this thread 中提出。然而,这些论点似乎站不住脚。
然而,不管是否返回一个对象,没有人会在迭代“完成”后检查一个值,对吧?例如。大多数人都会认为以下内容会记录迭代器返回的所有值:
function logIteratorValues(iterator) {
var next;
while(next = iterator.next(), !next.done)
console.log(next.value)
}
除非它没有,因为即使 done 是 false 迭代器可能仍然返回另一个值。考虑:
function* generator() {
yield 0;
return 1;
}
var iterator = generator();
var result0 = iterator.next();
var result1 = iterator.next();
console.log(`${result0.value}, ${result0.done}`) // 0, false
console.log(`${result1.value}, ${result1.done}`) // 1, true
在“完成”之后返回值的迭代器真的是迭代器吗?一只手拍的声音是什么?只是看起来很奇怪......
here 是关于我喜欢的生成器的深入帖子。与迭代集合的成员相比,很多时间都花在控制应用程序的流程上。
另一种可能的解释是 IEnumerable/IEnumerator 需要两个接口和三个方法,而 JS 社区更喜欢单一方法的简单性。这样他们就不必引入符号方法组的概念,也就是接口......
【问题讨论】:
-
您能否链接到说明需要返回 new 对象的规范?
-
您可能不会在这里得到有关特定语言设计决策的答案,因为从事规范工作的人不在这里。您应该直接与他们联系。
-
@Bergi:实际上,这仅描述了内置迭代器的行为。协议本身似乎不需要在每次迭代中都有一个新对象。
-
FWIW,这是一个重用结果对象的示例:jsfiddle.net/wp82n07o。 specification of the protocol 似乎不需要在每次迭代中返回一个 不同的 对象(据我所知)。所以看起来你可以只分配一个。但是,正如我之前提到的,如果您想对此进行澄清,我会联系 TC39 委员会的人员。
-
@FelixKling 这里有一些讨论:esdiscuss.org/topic/…,esdiscuss.org/topic/iterator-next-method-returning-new-object。我还发现重用对象会使编译器更难进行转义分析...
标签: javascript performance memory-management ecmascript-6 iterable