JS错误处理机制2019-08-19(2)

错误处理机制

一、Error实例对象

  • JavaScript 解析或运行时,一旦发生错误,引擎就会抛出一个错误对象。JavaScript 原生提供Error构造函数,所有抛出的错误都是这个构造函数的实例。
  • Error实例对象必须有message属性,表示出错时的提示信息。Error实例还提供namestack属性,分别表示错误的名称和错误的堆栈。但它们是非标准的,不是每种实现都有。
    message:错误提示信息
    name:错误名称(非标准属性)
    stack:错误的堆栈(非标准属性)

Error的六个派生对象:

  • SyntaxError 对象(语法错误)
    SyntaxError对象是解析代码时发生的语法错误。

  • ReferenceError 对象(引用错误)
    ReferenceError对象是引用一个不存在的变量时发生的错误。
    例如:将一个值分配给无法分配的对象,比如对函数的运行结果或者this赋值。

  • RangeError 对象(引用错误)
    RangeError对象是一个值超出有效范围时发生的错误
    主要有几种情况,一是数组长度为负数,二是Number对象的方法参数超出范围,以及函数堆栈超过最大值。

  • TypeError 对象(类型错误)
    TypeError对象是变量或参数不是预期类型时发生的错误
    例如: 对字符串、布尔值、数值等原始类型的值使用new命令

  • URIError 对象(编码错误)
    URIError对象是URI相关函数的参数不正确时抛出的错误

  • EvalError对象(全局错误)
    eval函数没有被正确执行时,会抛出EvalError错误。该错误类型已经不再使用了,只是为了保证与以前代码兼容,才继续保留。

以上这6种派生错误,连同原始的Error对象,都是构造函数。开发者可以使用它们,手动生成错误对象的实例。这些构造函数都接受一个参数,代表错误提示信息(message)。

二、throw 语句
throw语句的作用是手动中断程序执行,抛出一个错误。

if (x <= 0) {
  throw new Error('x 必须为正数');
}
// Uncaught ReferenceError: x is not defined

throw抛出的错误就是它的参数,这里是一个Error实例。
throw可以抛出任何类型的值。也就是说,它的参数可以是任何值。

// 抛出一个字符串
throw 'Error!';
// Uncaught Error!

// 抛出一个数值
throw 42;
// Uncaught 42

// 抛出一个布尔值
throw true;
// Uncaught true

// 抛出一个对象
throw {
  toString: function () {
    return 'Error!';
  }
};
// Uncaught {toString: ƒ}

对于 JavaScript 引擎来说,遇到throw语句,程序就中止了

三、try...catch结构

  • 一旦发生错误,程序就中止执行了。JavaScript 提供了try...catch结构,允许对错误进行处理,选择是否往下执行。
  • try语句包含了由一个或者多个语句组成的try块, 和至少一个catch子句或者一个finally子句的其中一个,或者两个兼有。
  • 三种形式的try声明:

1.try...catch

  1. try...finally

  2. try...catch...finally

try {
  throw new Error('出错了!');
} catch (e) {
  console.log(e.name + ": " + e.message);
  console.log(e.stack);
}
// Error: 出错了!
//   at <anonymous>:3:9
//   ...
  • catch子句包含try块中抛出异常时要执行的语句。即:想让try语句中的内容成功, 如果没成功,想控制接下来发生的事情,这时可以在catch语句中实现。 如果在try块中有任何一个语句(或者从try块中调用的函数)抛出异常控制立即转向catch子句。如果在try块中没有异常抛出,会跳过catch子句
  • catch代码块捕获错误之后,程序不会中断,会按照正常流程继续执行下去。
  • catch代码块之中,还可以再抛出错误,甚至使用嵌套try...catch结构。
var n = 100;

try {
  throw n;
} catch (e) {
  if (e <= 50) {
    // ...
  } else {
    throw e;
  }
}
// Uncaught 100
  • catch接受一个参数,表示try代码块抛出的值。
  • catch代码块之中可以加入判断语句 if...else。用于判断错误类型,进行不同的处理。
try {
  foo.bar();
} catch (e) {
  if (e instanceof EvalError) {
    console.log(e.name + ": " + e.message);
  } else if (e instanceof RangeError) {
    console.log(e.name + ": " + e.message);
  }
  // ...
}
  • finally子句在try块和catch之后执行但是在下一个try声明之前执行。无论是否有异常抛出或捕获它总是执行

四、finally 代码块

  • ry...catch结构允许在最后添加一个finally代码块,表示不管是否出现错误,都必需在最后运行的语句
function cleansUp() {
  try {
    throw new Error('出错了……');
    console.log('此行不会执行');
  } finally {
    console.log('完成清理工作');
  }
}

cleansUp()
// 完成清理工作
// Uncaught Error: 出错了……
//    at cleansUp (<anonymous>:3:11)
//    at <anonymous>:10:1

上面代码中,由于没有catch语句块,一旦发生错误,代码就会中断执行。中断执行之前,会先执行finally代码块,然后再向用户提示报错信息。

function idle(x) {
  try {
    console.log(x);
    return 'result';
  } finally {
    console.log('FINALLY');
  }
}

idle('hello')
// hello
// FINALLY

上面代码中,try代码块没有发生错误,而且里面还包括return语句,但是finally代码块依然会执行。而且,这个函数的返回值还是result

  • return语句的执行是排在finally代码之前,只是等finally代码执行完毕后才返回。
  • 下面是finally代码块用法的典型场景。
openFile();

try {
  writeFile(Data);
} catch(e) {
  handleError(e);
} finally {
  closeFile();
}

上面代码首先打开一个文件,然后在try代码块中写入文件,如果没有发生错误,则运行finally代码块关闭文件;一旦发生错误,则先使用catch代码块处理错误,再使用finally代码块关闭文件。

  • try...catch...finally这三者之间的执行顺序,例:
function f() {
  try {
    console.log(0);
    throw 'bug';
  } catch(e) {
    console.log(1);
    return true; // 这句原本会延迟到 finally 代码块结束再执行
    console.log(2); // 不会运行
  } finally {
    console.log(3);
    return false; // 这句会覆盖掉前面那句 return
    console.log(4); // 不会运行
  }

  console.log(5); // 不会运行
}

var result = f();
// 0
// 1
// 3

result
// false

上面例子中catch代码块结束执行之前,会先执行finally代码块。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容