try...catch
try...catch 语句由一个 try 块和一个 catch 块、一个 finally 块或两者组成。try 块中的代码首先执行,如果它抛出异常,则执行 catch 块中的代码。finally 块中的代码总是在控制流退出整个构造之前执行。
试一试
try {
nonExistentFunction();
} catch (error) {
console.error(error);
// Expected output: ReferenceError: nonExistentFunction is not defined
// (Note: the exact output may be browser-dependent)
}
语法
try {
tryStatements
} catch (exceptionVar) {
catchStatements
} finally {
finallyStatements
}
tryStatements-
要执行的语句。
catchStatements-
如果在
try块中抛出异常,则执行的语句。 exceptionVar可选-
一个可选的标识符或模式,用于保存关联
catch块捕获的异常。如果catch块不使用异常的值,你可以省略exceptionVar及其周围的括号。 finallyStatements-
在控制流退出
try...catch...finally构造之前执行的语句。这些语句无论是否抛出或捕获异常都会执行。
描述
try 语句总是以一个 try 块开头。然后,必须存在一个 catch 块或一个 finally 块。也可以同时存在 catch 和 finally 块。这为我们提供了 try 语句的三种形式
try...catchtry...finallytry...catch...finally
与诸如 if 或 for 等其他结构不同,try、catch 和 finally 块必须是块,而不是单个语句。
try doSomething(); // SyntaxError
catch (e) console.log(e);
catch 块包含指定如果在 try 块中抛出异常时该怎么做的语句。如果 try 块中的任何语句(或从 try 块内部调用的函数)抛出异常,则控制会立即转移到 catch 块。如果在 try 块中没有抛出异常,则 catch 块将被跳过。
finally 块总是在控制流退出 try...catch...finally 构造之前执行。它总是执行,无论是否抛出或捕获异常。
你可以嵌套一个或多个 try 语句。如果内部的 try 语句没有 catch 块,则使用外部 try 语句的 catch 块。
你还可以使用 try 语句来处理 JavaScript 异常。有关 JavaScript 异常的更多信息,请参阅 JavaScript 指南。
捕获绑定
当在 try 块中抛出异常时,exceptionVar(即 catch (e) 中的 e)会保存异常值。你可以使用此绑定来获取有关已抛出异常的信息。此绑定仅在 catch 块的作用域中可用。
它不必是单个标识符。你可以使用解构模式一次分配多个标识符。
try {
throw new TypeError("oops");
} catch ({ name, message }) {
console.log(name); // "TypeError"
console.log(message); // "oops"
}
catch 子句创建的绑定与 catch 块具有相同的范围,因此在 catch 块中声明的任何变量都不能与 catch 子句创建的绑定同名。(此规则有一个例外,但这是一种已废弃的语法。)
try {
throw new TypeError("oops");
} catch ({ name, message }) {
var name; // SyntaxError: Identifier 'name' has already been declared
let message; // SyntaxError: Identifier 'message' has already been declared
}
异常绑定是可写的。例如,你可能希望规范化异常值,以确保它是一个 Error 对象。
try {
throw "Oops; this is not an Error object";
} catch (e) {
if (!(e instanceof Error)) {
e = new Error(e);
}
console.error(e.message);
}
如果你不需要异常值,可以将其与周围的括号一起省略。
function isValidJSON(text) {
try {
JSON.parse(text);
return true;
} catch {
return false;
}
}
finally 块
finally 块包含在 try 块和 catch 块执行之后,但在 try...catch...finally 块之后的语句之前执行的语句。控制流将始终进入 finally 块,其执行方式如下:
- 紧接着
try块正常执行完毕后(且没有抛出异常); - 紧接着
catch块正常执行完毕后; - 紧接着在
try块或catch块中将退出该块的控制流语句(return、throw、break、continue)执行之前。
即使 try 块抛出异常,并且没有 catch 块来处理该异常,finally 块仍会执行。在这种情况下,异常仍会在 finally 块执行完毕后立即抛出。
以下示例展示了 finally 块的一种用例。代码打开一个文件,然后执行使用该文件的语句;finally 块确保文件在使用后始终关闭,即使抛出异常也是如此。
openMyFile();
try {
// tie up a resource
writeMyFile(theData);
} finally {
closeMyFile(); // always close the resource
}
finally 块中的控制流语句(return、throw、break、continue)将“屏蔽”try 块或 catch 块的任何完成值。在此示例中,try 块试图返回 1,但在返回之前,控制流首先交给 finally 块,因此返回的是 finally 块的返回值。
function doIt() {
try {
return 1;
} finally {
return 2;
}
}
doIt(); // returns 2
在 finally 块中包含控制流语句通常不是一个好主意。只将其用于清理代码。
示例
无条件 catch 块
当使用 catch 块时,如果从 try 块内部抛出任何异常,catch 块就会执行。例如,当以下代码中发生异常时,控制将转移到 catch 块。
try {
throw new Error("My exception"); // generates an exception
} catch (e) {
// statements to handle any exceptions
logMyErrors(e); // pass exception object to error handler
}
catch 块指定一个标识符(上面示例中的 e)来保存异常的值;此值仅在 catch 块的作用域中可用。
条件 catch 块
你可以通过将 try...catch 块与 if...else if...else 结构结合来创建“条件 catch 块”,如下所示:
try {
myRoutine(); // may throw three types of exceptions
} catch (e) {
if (e instanceof TypeError) {
// statements to handle TypeError exceptions
} else if (e instanceof RangeError) {
// statements to handle RangeError exceptions
} else if (e instanceof EvalError) {
// statements to handle EvalError exceptions
} else {
// statements to handle any unspecified exceptions
logMyErrors(e); // pass exception object to error handler
}
}
一个常见的用例是只捕获(并静默处理)一小部分预期错误,然后在其他情况下重新抛出错误
try {
myRoutine();
} catch (e) {
if (e instanceof RangeError) {
// statements to handle this very common expected error
} else {
throw e; // re-throw the error unchanged
}
}
这可能模仿其他语言(如 Java)的语法
try {
myRoutine();
} catch (RangeError e) {
// statements to handle this very common expected error
}
// Other errors are implicitly re-thrown
嵌套的 try 块
首先,让我们看看会发生什么
try {
try {
throw new Error("oops");
} finally {
console.log("finally");
}
} catch (ex) {
console.error("outer", ex.message);
}
// Logs:
// "finally"
// "outer" "oops"
现在,如果我们通过添加一个 catch 块已经在内部 try 块中捕获了异常
try {
try {
throw new Error("oops");
} catch (ex) {
console.error("inner", ex.message);
} finally {
console.log("finally");
}
} catch (ex) {
console.error("outer", ex.message);
}
// Logs:
// "inner" "oops"
// "finally"
现在,我们重新抛出错误。
try {
try {
throw new Error("oops");
} catch (ex) {
console.error("inner", ex.message);
throw ex;
} finally {
console.log("finally");
}
} catch (ex) {
console.error("outer", ex.message);
}
// Logs:
// "inner" "oops"
// "finally"
// "outer" "oops"
任何给定的异常都只会被最近的外部 catch 块捕获一次,除非它被重新抛出。当然,在“内部”块中引发的任何新异常(因为 catch 块中的代码可能会做一些抛出异常的事情)将由“外部”块捕获。
从 finally 块返回
如果 finally 块返回一个值,则该值将成为整个 try-catch-finally 语句的返回值,而不管 try 和 catch 块中的任何 return 语句。这包括在 catch 块内抛出的异常。
(() => {
try {
try {
throw new Error("oops");
} catch (ex) {
console.error("inner", ex.message);
throw ex;
} finally {
console.log("finally");
return;
}
} catch (ex) {
console.error("outer", ex.message);
}
})();
// Logs:
// "inner" "oops"
// "finally"
外部的“oops”没有被抛出,因为 finally 块中的返回。对于从 catch 块返回的任何值,也是如此。
规范
| 规范 |
|---|
| ECMAScript® 2026 语言规范 # sec-try-statement |
浏览器兼容性
加载中…