在草案ECMAScript 6中;s使用StopIteration异常来表示迭代结束的基本原理
In Draft ECMAScript 6, what's the rationale behind using StopIteration exception to signal the end of iteration?
在ECMAScript 6规范草案中,使用StopIteration
异常来表示迭代结束,而不是使用专用方法(Java/Scala中的hasNext
和C#中的MoveNext
)来检查迭代结束,其原理是什么。
撇开潜在的性能问题不谈,在我看来,异常不应该被用于一些实际上不是异常的东西。
我并不声称这个答案具有权威性。相反,这只是我对我读到的关于迭代器的各种讨论和/或我自己的想法的回忆。。。不幸的是,我没有一个来源列表(很久以前),也无法轻松生成一个(因为有时即使在谷歌上搜索也需要很多时间)。
StopIteration
名称StopIteration
和许多语义都源自python。
PEP234有一些关于替代方法的评论:
有人质疑是否有一个例外标志着迭代并不太昂贵。StopIteration异常已被提出:一个特殊值End为了发出结束信号,函数end()测试迭代器是否已完成,甚至重复使用IndexError异常。
一个特殊值的问题是,如果一个序列包含该特殊值,则该序列上的循环将在没有任何警告的情况下过早结束。如果与以null结尾的C字符串并没有教会我们这个问题可以引起,想象一下Python内省工具的麻烦将对所有内置名称的列表进行迭代,假设特殊的End值是一个内置名称!
调用end()函数需要每个调用两次迭代。两个电话比一个电话贵得多加上一个异常测试。尤其是在时间紧迫的时候for循环可以非常廉价地测试异常。
重用IndexError可能会导致混乱,因为它可能是真正的错误,将通过结束循环来掩盖过早地。
hasNext()
Java的hasNext()
只是一个"奖励"。然而,Java的next()
有自己的StopIteration
风格,称为NoSuchElementException
。
hasNext()
即使不是不可能,也很难实现,最好用以下生成器来证明:
var i = 0;
function gen() {
yield doSomethingDestructive();
if (!i) {
yield doSomethingElse();
}
}
您将如何实现hasNext()
?你不能简单地"窥探"生成器,因为它实际上会执行doSomethingDestructive()
,而你并不打算这样做,否则你一开始就会调用next()
。
因此,你必须编写一些代码分析器,它必须始终可靠地证明给定的代码在以某种状态运行时总是会产生收益或不收益(停止问题)。因此,即使您可以编写类似的内容,状态也可能在.hasNext()
和随后的.next()
之间发生变化。
hasNext()
在以下示例中会返回什么:
var g = gen();
g.next();
if (g.hasNext()) {
++i;
alert(g.next());
}
在那个时候CCD_ 18将是正确的答案。然而,随后的.next()
会抛出,用户可能很难弄清楚为什么。。。
你可以告诉人们:"不要在迭代器实现中做以下事情"(契约)。人们会经常打断并抱怨。
因此,在我看来,hasNext()
考虑不周,很容易编写错误的代码。
.MoveNext()
C#
与.next()
几乎相同,只是返回值指示是否真的有下一个项目,而不是异常。
然而,有一个重要的区别:您需要将当前项存储在迭代器本身中,例如C#中的.Current
,这可能会不必要地延长当前项的寿命:
var bufferCtor = (function gen() {
for(;;) {
yield new ArrayBuffer(1<<20); // buffer of size 1 megabyte
}
})();
setInterval(function() {
// MoveNext scheme
bufferCtor.MoveNext(); // Not actually Javascript
var buf = bufferCtor.Current; // Not actually Javascript
// vs. StopIteration scheme
var buf = bufferCtor.next();
}, 60000); // Each minute
好吧,这个例子有点做作,但我相信在实际的用例中,生成器/迭代器会返回一些占用大量空间或占用资源的东西。
在StopIteration
方案中,一旦buf
超出范围,就可以对其进行垃圾收集。在.MoveNext()
中,在再次调用.next()
之前,它不能被垃圾收集,因为.Current
仍将保留对它的引用
结论
在我看来,在所提出的备选方案中,StopIteration
方案是最不容易出错和最不含糊的方法。如果我没有记错的话,蟒蛇和es-6人也有同样的想法。
- 如何在javascript中迭代数字列表
- JS:检查URL中的参数,然后迭代一个参数为var的函数
- 如何迭代Array.prototype函数
- 如何使用jquery迭代具有相同属性的html元素并查找onclick事件
- 在ejs-partial中对JSON对象进行迭代
- 如何在DataTables 2.1中迭代对象数组
- 使用递归属性迭代保留属性结构
- 正在停止.在jquery中的特定时间间隔内,每次迭代的每次执行
- 如果30秒未单击,请应用CSS一次,将其删除,然后重新迭代
- 主干-从模板中迭代的集合中获取特定的模型
- 创建一个方法,通过一个窗口进行迭代并获取Titanium中的所有控件
- 什么's是在javascript中迭代项的最佳方式
- 为什么这只是迭代 HTMLCollection 的奇怪元素
- 是否“;对于的“;循环迭代遵循JavaScript中的数组顺序
- 在草案ECMAScript 6中;s使用StopIteration异常来表示迭代结束的基本原理
- 当到达数据对象结束时停止迭代
- 在每次迭代时向DOM添加一个元素,而不是在循环结束时添加全部元素
- Javascript for循环直到循环结束才执行函数,然后迭代函数n次
- 在关联数组上的for in迭代的控制台输出结束时未定义
- javascript/jquery:迭代调用函数;等待之前的通话结束