try...catch
通常,如果发生错误,脚本就会“死亡”(立即停止),并在控制台将错误打印出来。
但是有一种语法结构 try...catch,它使我们可以“捕获(catch)”错误,因此脚本可以执行更合理的操作,而不是死掉。
语法:
try {
// 代码...
} catch (err) {
// 错误捕获
}它按照以下步骤执行:
- 首先,执行
try {...}中的代码。 - 如果这里没有错误,则忽略
catch (err):执行到try的末尾并跳过catch继续执行。 - 如果这里出现错误,则
try执行停止,控制流转向catch (err)的开头。变量err(我们可以使用任何名称)将包含一个error 对象,该对象包含了所发生事件的详细信息。
try {
shit;
} catch (error) {
console.log('error ' + error);//error ReferenceError: shit is not defined
}try...catch 只能处理有效代码中出现的错误。这类错误被称为“运行时的错误(runtime errors)”,有时被称为“异常(exceptions)”。 它必须是有效的 JavaScript 代码。
如果代码包含语法错误,那么 try..catch 将无法正常工作,例如含有不匹配的花括号
如果在“计划的(scheduled)”代码中发生异常,例如在 setTimeout 中,则 try...catch 不会捕获到异常:
try {
setTimeout(function () {
try {
noSuchVariable;
} catch (error) {
console.log('内部');//
}
}, 1000);
} catch (err) {
console.log("不工作");//
}引擎是同步执行的,所以在执行到setTimeout的时候已经离开了try,为了捕获这个错误,try必须在setTimeout的内部,包裹住可能发生错误的位置。
Error对象
对于所有内建的 error,error 对象具有两个主要属性:
name Error 名称。例如,对于一个未定义的变量,名称是 "ReferenceError"。
message 关于 error 的详细文字描述。
还有其他非标准的属性在大多数环境中可用。其中被最广泛使用和支持的是: stack 当前的调用栈:用于调试目的的一个字符串,其中包含有关导致 error 的嵌套调用序列的信息。
如果我们不需要 error 的详细信息,catch 也可以忽略它
使用throw会生成一个错误对象,并且抛出。在javascript中有很多的内建构造函数,Error,SyntaxError,ReferenceError,TypeError 等,用来构造一个错误对象。对于内建的 error(不是对于其他任何对象,仅仅是对于 error),name 属性刚好就是构造器的名字。message 则来自于参数(argument)。我们也可以自己来写:
let json = '{ "age": 30 }'; // 不完整的数据
try {
let user = JSON.parse(json); // <-- 没有 error
if (!user.name) {
throw new SyntaxError("数据不全:没有 name"); // (*)
}
alert(user.name);
} catch (err) {
alert("JSON Error: " + err.message); // JSON Error: 数据不全:没有 name
}再次抛出:我们可以使用 instanceof 操作符判断错误类型
- Catch 捕获所有 error。
- 在
catch (err) {...}块中,我们对 error 对象err进行分析。 - 如果我们不知道如何处理它,那我们就
throw err。
function readData() {
let json = '{ "age": 30 }';
try {
// ...
blabla(); // error!
} catch (err) {
// ...
if (!(err instanceof SyntaxError)) {
throw err; // 再次抛出(不知道如何处理它)
}
}
}
try {
readData();
} catch (err) {
alert( "External catch got: " + err ); // 捕获了它!
}抛出的错误再次进行捕捉,使用外层的catch来处理
try...catch 结构可能还有一个代码子句(clause):finally。 如果它存在,它在所有情况下都会被执行:
try之后,如果没有 error,catch之后,如果有 error。
try {
... 尝试执行的代码 ...
} catch (err) {
... 处理 error ...
} finally {
... 总是会执行的代码 ...
}finally 子句适用于 try...catch 的 任何 出口。这包括显式的 return。
在下面这个例子中,在 try 中有一个 return。在这种情况下,finally 会在控制转向外部代码前被执行 :
function func() {
try {
return 1;
} catch (err) {
/* ... */
} finally {
alert( 'finally' );
}
}
alert( func() ); // 先执行 finally 中的 alert,然后执行这个 alert没有 catch 子句的 try...finally 结构也很有用。当我们不想在原地处理 error(让它们掉出去吧),但是需要确保我们启动的处理需要被完成时,我们应当使用它
function func() {
// 开始执行需要被完成的操作(比如测量)
try {
// ...
} finally {
// 完成前面我们需要完成的那件事,即使 try 中的执行失败了
}
}自定义Error,Error的继承
class ValidationError extends Error {
constructor(message) {
super(message); // (1)
this.name = "ValidationError"; // (2)
}
}
try {
let user = readUser('{ "age": 25 }');
} catch (err) {
if (err instanceof ValidationError) {
alert("Invalid data: " + err.message); // Invalid data: No field: name
} else if (err instanceof SyntaxError) { // (*)
alert("JSON Syntax Error: " + err.message);
} else {
throw err; // 未知的 error,再次抛出 (**)
}
}还有,没有学完。