5.6 try..finally
try..catch 对我们来说可能已经非常熟悉了。但你是否知道 try 可以和 catch 或者 finally 配对使用,并且必要时两者可同时出现?
finally 中的代码总是会在 try 之后执行,如果有 catch 的话则在 catch 之后执行。也可以将 finally 中的代码看作一个回调函数,即无论出现什么情况最后一定会被调用。
如果 try 中有 return 语句会出现什么情况呢? return 会返回一个值,那么调用该函数并得到返回值的代码是在 finally 之前还是之后执行呢?
function foo() { try { return 42; } finally { console.log( "Hello" ); } console.log( "never runs" ); } console.log( foo() ); // Hello // 42
这里 return 42 先执行,并将 foo() 函数的返回值设置为 42 。然后 try 执行完毕,接着执行 finally 。最后 foo() 函数执行完毕,console.log(..) 显示返回值。
try 中的 throw 也是如此:
function foo() { try { throw 42; } finally { console.log( "Hello" ); } console.log( "never runs" ); } console.log( foo() ); // Hello // Uncaught Exception: 42
如果 finally 中抛出异常(无论是有意还是无意),函数就会在此处终止。如果此前 try 中已经有 return 设置了返回值,则该值会被丢弃:
function foo() { try { return 42; } finally { throw "Oops!"; } console.log( "never runs" ); } console.log( foo() ); // Uncaught Exception: Oops!
continue 和 break 等控制语句也是如此:
for (var i=0; i<10; i++) { try { continue; } finally { console.log( i ); } } // 0 1 2 3 4 5 6 7 8 9
continue 在每次循环之后,会在 i++ 执行之前执行 console.log(i) ,所以结果是 0..9 而非 1..10 。
ES6 中新加入了 yield (参见本书的“异步和性能”部分),可以将其视为 return 的中间版本。然而与 return 不同的是,yield 在 generator(ES6 的另一个新特性)重新开始时才结束,这意味着 try { .. yield .. } 并未结束,因此 finally 不会在 yield 之后立即执行。
finally 中的 return 会覆盖 try 和 catch 中 return 的返回值:
function foo() { try { return 42; } finally { // 没有返回语句,所以没有覆盖 } } function bar() { try { return 42; } finally { // 覆盖前面的 return 42 return; } } function baz() { try { return 42; } finally { // 覆盖前面的 return 42 return "Hello"; } } foo(); // 42 bar(); // undefined baz(); // Hello
通常来说,在函数中省略 return 的结果和 return; 及 return undefined; 是一样的,但是在 finally 中省略 return 则会返回前面的 return 设定的返回值。
事实上,还可以将 finally 和带标签的 break 混合使用(参见 5.1.3 节)。例如:
function foo() { bar: { try { return 42; } finally { // 跳出标签为bar的代码块 break bar; } } console.log( "Crazy" ); return "Hello"; } console.log( foo() ); // Crazy // Hello
但切勿这样操作。利用 finally 加带标签的 break 来跳过 return 只会让代码变得晦涩难懂,即使加上注释也是如此。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论