JS中的Error对象及使用JSON.stringify()序列化Error问题
作者:阿斯巴甜嘛
一. 错误对象的类型
Error
: 所有错误类型的父类型;SyntaxError
: 语法错误,表示程序的语法使用错误;
console.log(" "" ") ; // Uncaught SyntaxError: missing ) after argument list
ReferenceError
: 引用错误,表示引用的变量不存在;
console.log(a); // Uncaught ReferenceError: a is not defined
TypeError
: 类型错误,表示使用了错误的数据类型
let a; console.log(a.name); // Uncaught TypeError: Cannot read properties of undefined (reading 'name') RangeError:范围错误, 数据值不在其所允许的范围内(函数递归调用容易出现此错误) // 保留小数点多少位 (10.24).toFixed(-1); // toFixed() digits argument must be between 0 and 100 URIError: URI错误,向全局 URI 处理函数(decodeURI、decodeURIComponent)传递一个不合法的URI时,URIError 错误会被抛出 // 解码URI地址 错误:格式不正确 console.log(decodeURI("%") ); // URIError: URI malformed
以上都是不同错误类型的 Error构造函数,能通过new 创建错误对象
错误处理
捕获错误 try ... catch
try { // 正常书写的程序代码(可能会出错的代码) } catch (err) { // err: try中执行语句发生错误时,自动创建err错误对象,并将错误信息保存在对象err中 // 执行错误处理 } finally { // 一般用于释放资源 // finally 可有可无,因为try ... catch 之后的代码本来就会执行 }
- 放在try...catch中的代码,执行效率会降低;
- 尽量少的将代码放入try...catch中;
- 如果可提前预知错误原因,可用 if...else 代替,提前预防错误。
抛出错误 throw error
通过throw,主动抛出异常错误;
throw new Error("错误信息");
错误对象的属性:
name
属性: 错误类型;message
属性: 错误相关的描述信息;stack
属性:函数调用栈记录信息(错误相关信息,错误出现的位置)
try{ console.log(a); } catch (err) { console.log(err.name); // ReferenceError console.log(err.message); // a is not defined }
二.使用JSON.stringfy()去序列化一个 Error
最近在做Node 服务端 测试的时候,遇到 打log JSON.stringify(error)为{}的问题,这样的情况导致根本无法定位到具体问题。
例如:
JSON.stringify()
: 它能够方便地把一个对象转化成字符串;
但是,它也有一个较大的缺点,就是无法直接处理如Error 这类的对象。
const err = new Error('This is an error') JSON.stringify(err) // '{}'
在控制台运行上述代码后会发现,JSON.stringify() 的结果是一个字符串的 "{}",里面没有任何有效内容。这是否意味着 JSON.stringify() 确实无法处理 Error 呢?下面我们来看看在 MDN 里这个函数是如何定义的。
MDN 定义
JSON.stringify()将值转换为相应的JSON格式:
- 转换值如果有toJSON()方法,该方法定义什么值将被序列化。
- 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
- 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
- undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。函数、undefined被单独转换时,会返回undefined,如JSON.stringify(function(){}) or JSON.stringify(undefined).
- 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。
- 所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。
- Date日期调用了toJSON()将其转换为了string字符串(同Date.toISOString()),因此会被当做字符串处理。
- NaN和Infinity格式的数值及null都会被当做null。
- 其他类型的对象,包括Map/Set/weakMap/weakSet,仅会序列化可枚举的属性。
“仅会序列化可枚举的属性”,是什么意思呢?众所周知,在 JS 的世界中一切皆对象,对象有着不同的属性,这些属性是否可枚举,我们用 enumerable 来定义.
对象属性的 enumerable
举个例子,我们用 obj = { a: 1, b: 2, c: 3 } 来定义一个对象,然后设置它的 c 属性为“不可枚举”,看看效果会如何:
首先看处理前的效果:
const obj = {a: 1,b: 2,c: 3}; JSON.stringify(obj) // '{"a":1,"b":2,"c":3}'
再看处理后的效果:
const obj = { a: 1, b: 2, c: 3 } Object.defineProperty(obj, 'c', { value: 3, enumerable: false }) JSON.stringify(obj) // => "{"a":1,"b":2}"
可以看到,在对 c 属性设置为不可枚举以后,JSON.stringify() 便不再对其进行序列化。
我们把问题再深入一些,有没有办法能够获取一个对象中包含不可枚举在内的所有属性呢?答案是使用 Object.getOwnPropertyNames() 方法。
依然是刚刚被改装过的 obj 对象,我们来看看它所包含的所有属性:
Object.getOwnPropertyNames(obj) // => ["a", "b", "c"]
不可枚举的 c 属性也被获取到了!
用同样的方法,我们来看看一个 Error 都包含哪些属性:
const err = new Error('This is an error') Object.getOwnPropertyNames(err) // => ["stack", "message"]
可以看到,Error 包含了 stack 和 message 两个属性,它们均可以使用点运算符 . 从 err 实例里面拿到。
既然我们已经能够获取 Error 实例的不可枚举属性及其内容,那么距离使用 JSON.stringify() 序列化 Error 也已经不远了!
JSON.stringify() 的第二个参数
JSON.stringify() 可以接收三个参数:
语法:
JSON.stringify(value[, replacer [, space]])
value
- 将要序列化成 一个JSON 字符串的值。
replacer
可选- 如果该参数是一个函数,则在序列化过程中,被序列化的值的每个属性都会经过该函数的转换和处理;如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中;如果该参数为null或者未提供,则对象所有的属性都会被序列化。
space
可选- 指定缩进用的空白字符串,用于美化输出(pretty-print);如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格;如果该参数为字符串(字符串的前十个字母),该字符串将被作为空格;如果该参数没有提供(或者为null)将没有空格。
- 返回值 节
- 一个表示给定值的JSON字符串。
我们来看 replacer 的用法:
……如果该参数是一个数组,则只有包含在这个数组中的属性名才会被序列化到最终的 JSON 字符串中……
依然使用上文的 obj 为例子:
const obj = { a: 1, b: 2, c: 3 } Object.defineProperty(obj, 'c', { value: 3, enumerable: false }) JSON.stringify(obj, ['a', 'c']) // => "{"a":1,"c":3}"
可以看到,我们在 replacer 中指定了要序列化 a 和 c 属性,输出结果也是只有这两个属性的值,且不可枚举的 c 属性也被序列化了!守得云开见月明,Error 对象被序列化的方法也就出来了:
const err = new Error('This is an error') JSON.stringify(err, Object.getOwnPropertyNames(err), 2) // => // "{ // "stack": "Error: This is an error\n at <anonymous>:1:13", // "message": "This is an error" // }"
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。