JavaScript Error对象详解与JSON.stringify序列化异常处理方案

作者:拾光

时间:2026-10-26

浏览:241

本文详解JavaScript中Error对象的六种类型及属性,重点分析JSON.stringify序列化Error返回空对象的原因。通过探讨对象属性的enumerable特性,利用Object.getOwnPropertyNames获取不可枚举属性,并结合JSON.stringify的replacer参数,实现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

上述均为各类错误的构造函数,可通过 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 服务端测试期间,遭遇通过 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(){}) 或 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"
// }"

以上为个人经验,希望能给大家一个参考,也希望大家多多支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章