LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 142|回复: 0

扩展 Error

[复制链接]
发表于 2024-1-15 16:56:06 | 显示全部楼层 |阅读模式
例如,让我们考虑一个函数 readUser(json),该函数应该读取带有用户数据的 JSON。

这里是一个可用的 json 的例子:

let json = `{ "name": "John", "age": 30 }`;
在函数内部,我们将使用 JSON.parse。如果它接收到格式不正确的 json,就会抛出 SyntaxError。但是,即使 json 在语法上是正确的,也不意味着该数据是有效的用户数据,对吧?因为它可能丢失了某些必要的数据。例如,对用户来说,必不可少的是 name 和 age 属性。

我们的函数 readUser(json) 不仅会读取 JSON,还会检查(“验证”)数据。如果没有所必须的字段,或者(字段的)格式错误,那么就会出现一个 error。并且这些并不是 SyntaxError,因为这些数据在语法上是正确的,这些是另一种错误。我们称之为 ValidationError,并为之创建一个类。这种类型的错误也应该包含有关违规字段的信息。

我们的 ValidationError 类应该继承自 Error 类。

Error 类是内建的,但这是其近似代码,所以我们可以了解我们要扩展的内容:

// JavaScript 自身定义的内建的 Error 类的“伪代码”
class Error {
  constructor(message) {
    this.message = message;
    this.name = "Error"; // (不同的内建 error 类有不同的名字)
    this.stack = <call stack>; // 非标准的,但大多数环境都支持它
  }
}
现在让我们从其中继承 ValidationError,并尝试进行运行:

class ValidationError extends Error {
  constructor(message) {
    super(message); // (1)
    this.name = "ValidationError"; // (2)
  }
}

function test() {
  throw new ValidationError("Whoops!");
}

try {
  test();
} catch(err) {
  alert(err.message); // Whoops!
  alert(err.name); // ValidationError
  alert(err.stack); // 一个嵌套调用的列表,每个调用都有对应的行号
}
请注意:在 (1) 行中我们调用了父类的 constructor。JavaScript 要求我们在子类的 constructor 中调用 super,所以这是必须的。父类的 constructor 设置了 message 属性。

父类的 constructor 还将 name 属性的值设置为了 "Error",所以在 (2) 行中,我们将其重置为了右边的值。

让我们尝试在 readUser(json) 中使用它吧:

class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = "ValidationError";
  }
}

// 用法
function readUser(json) {
  let user = JSON.parse(json);

  if (!user.age) {
    throw new ValidationError("No field: age");
  }
  if (!user.name) {
    throw new ValidationError("No field: name");
  }

  return user;
}

// try..catch 的工作示例

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,再次抛出 (**)
  }
}
上面代码中的 try..catch 块既处理我们的 ValidationError 又处理来自 JSON.parse 的内建 SyntaxError。

请看一下我们是如何使用 instanceof 来检查 (*) 行中的特定错误类型的。

我们也可以看看 err.name,像这样:

// ...
// instead of (err instanceof SyntaxError)
} else if (err.name == "SyntaxError") { // (*)
// ...
使用 instanceof 的版本要好得多,因为将来我们会对 ValidationError 进行扩展,创建它的子类型,例如 PropertyRequiredError。而 instanceof 检查对于新的继承类也适用。所以这是面向未来的做法。

还有一点很重要,在 catch 遇到了未知的错误,它会在 (**) 行将该错误再次抛出。catch 块只知道如何处理 validation 错误和语法错误,而其他错误(由代码中的拼写错误或其他未知原因导致的)应该被扔出(fall through)。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表