有几次我被告知在javascript中使用异常是“坏”的。还没有真正被告知为什么这很糟糕,但我不应该使用休息,继续并返回。
哪个好,除了我不需要返回/中断/继续,我需要抛出。我有一个案例,我有迭代器函数嵌套在一起,每个都在调用时返回下一个值,所以我使用一个异常来表明没有什么可以迭代:似乎是一种逻辑方式来做,使代码干净并且在实践中完美地运作。是否真的有任何理由不在js中使用例外?
第二个问题,当我使用异常时,我应该抛出什么样的对象?对于错误,我显然会抛出Error的实例,但是对于特殊情况(停止迭代等),我需要一种快速方法来检查那些特定的异常,而我所做的只是定义一个空的命名函数(函数StopIteration(){因为函数通过引用进行比较,我总是可以检查它是否是我的特例或者我应该重新抛出。在js中有更好或更多的自我方式吗?我是否真的应该尝试重构我的代码以避免使用异常?
谢谢
答案 0 :(得分:3)
听起来你正在使用嵌套循环搜索多维空间,这是一个相当常见的程序。当发现目标然后被最外层循环周围的“捕获”块捕获时,从最内层循环抛出异常是很诱人的,但这通常被认为是不好的练习。
语言设计者意识到这个缺陷,因此他们允许我们给循环结构赋予标签(名称),以便我们可以从它们中断(或继续它们)。考虑这个例子:
function findValueInMatrix(value, matrix) {
var r, c, coords, rows=matrix.length, cols=matrix[0].length;
found: // Label the outer loop as "found" so we can break from it.
for (r=0; r<rows; r++) {
for (c=0; c<cols; c++) {
if (matrix[r][c] == value) {
coords = [r, c]
break found; // Exit the loop labeled "found".
}
}
}
return coords;
}
您可以在this post about breaking from nested loops中找到更多信息。
此jsPerf test case还表明,打破标签名义上比抛出异常更快(大概在大多数浏览器中)。
答案 1 :(得分:2)
异常处理通常比正常评估慢,仅适用于异常情况
对于停止迭代,你最好为结束条件定义一个hasNext或isEmpty函数,或者在没有更多元素时返回一个sentinel值(如undefined
),这样循环变为
//with hasNext
while(it.hasNext()){
var val = it.next();
//...
}
//or with a sentinal undefined
while( (val = it.next()) !== undefined){
//...
}
答案 2 :(得分:0)
对于某些人来说,抛出异常以表明没有更多的价值观是一种糟糕的风格; 例外行为的例外情况。
此外,异常处理通常比简单测试慢。
如果不是每次都创建抛出的实例,那么差异实际上很小(甚至可能根本不存在)。所以有一个常数StopIteration
并抛出它实际上非常快。
对于您的问题,您可能希望看到https://developer.mozilla.org/en/JavaScript/Guide/Iterators_and_Generators(他们使用例外来停止迭代)。 我发现在动态类型语言中,异常也用于此类目的。
答案 3 :(得分:-1)
抛出异常以突破嵌套的递归搜索/漫游是最简单的以及更多优雅方式。
假设您走树,递归调用函数来处理当前节点,再次为其每个子节点调用,依此类推。
当您处理每个节点时,您可能希望完全打破整个调用堆栈并返回找到的值(或停止迭代 general),打破在之前调用中等待的所有循环。请注意,之前的这些调用在处理过程中可能会很昂贵。记忆,但如果你“找到”你的结果就没用了。抛出异常是实现这一目标的最有效和最简单的方法,但当然需要注意。
对于简单(甚至嵌套)的循环来说,它是一种矫枉过正,并被正当地吹捧为反模式。