JavaScript中抛出错误时如何在控制台打印格式化可展开对象?
问题背景
console.error()(或console.log())支持可变长度参数列表,可以友好打印对象、数组的结构化内容,示例代码如下:
const spaghettio = {sauce: 'arrabiata', cheese: 'gorgonzola'} console.log(`Uh oh,`, spaghettio)
这种方式打印的对象支持在控制台展开查看所有键值,调试大对象时非常方便:
但如果要抛出正式的Error对象,没法直接复用这个打印能力,常见的写法有两种:
// 写法1:先打日志再抛错,代码重复,且错误消息里对象格式化失效 console.error(`Uh oh`, spaghettio) throw new Error(`Uh oh: ${spaghettio}`) // 写法2:用JSON序列化,没法展示函数、undefined值,遇到循环引用会报错,也不支持控制台展开 throw new Error(`Uh oh: ${JSON.stringify(spaghettio)}`)
两种写法都有问题:要么代码重复,要么格式化效果远不如原生console的展示效果。
最优实现方案
直接封装统一的格式化错误抛出工具函数,一次实现两个目标:复用console原生的友好格式化打印能力,同时抛出标准Error对象,避免重复代码。
基础通用版(全环境兼容)
这个版本完全保留console原生的对象打印体验,同时把结构化调试数据挂在错误实例上,方便上层捕获时使用:
/** * 抛出标准错误,同时在控制台输出可展开的友好格式化调试内容 * @param {string} message 错误提示文本 * @param {...any} debugParams 需要附加展示的任意类型调试参数 */ function throwFormattedError(message, ...debugParams) { // 直接复用console.error的可变参数逻辑,打印和原生体验完全一致的可展开内容 console.error(message, ...debugParams) // 抛出标准错误,同时把调试数据挂在标准cause字段上(ES2022原生支持) throw new Error(message, { cause: debugParams }) } // 调用示例 const spaghettio = {sauce: 'arrabiata', cheese: 'gorgonzola'} throwFormattedError('Uh oh', spaghettio)
这个方案的优势:
- 零重复代码:全局只需要封装一次,所有需要抛错带对象调试的场景直接调用即可
- 格式化效果拉满:控制台打印的内容和直接写
console.error完全一致,支持嵌套对象展开、查看属性类型、原型链,不会出现[object Object],遇到循环引用、函数、undefined值也不会序列化失败 - 符合标准规范:用ES原生支持的
cause字段存调试数据,上层catch到错误后可以直接通过err.cause拿到结构化的原始数据,不用反序列化字符串,做日志上报、二次调试都很方便
增强版:让错误消息字符串也带格式化内容
如果希望错误本身的message字符串里也能看到对象内容(比如日志上报时不依赖控制台交互),可以针对运行环境加字符串格式化逻辑:
Node.js环境
Node内置了util.inspect方法,可以把对象转成和控制台展示几乎一致的格式化字符串,支持设置递归深度、展示隐藏属性:
import util from 'node:util' function throwFormattedError(message, ...debugParams) { console.error(message, ...debugParams) const formattedDebugContent = debugParams .map(item => typeof item === 'object' && item !== null ? util.inspect(item, { depth: null }) : String(item) ) .join(' ') throw new Error(`${message} ${formattedDebugContent}`, { cause: debugParams }) }
浏览器环境
浏览器没有内置util.inspect,可以用带缩进的JSON.stringify做基础字符串格式化,兜底处理循环引用的场景:
function stringifyDebugValue(value) { if (typeof value !== 'object' || value === null) return String(value) try { return JSON.stringify(value, null, 2) } catch (err) { return String(value) } } function throwFormattedError(message, ...debugParams) { console.error(message, ...debugParams) const formattedDebugContent = debugParams.map(stringifyDebugValue).join(' ') throw new Error(`${message} ${formattedDebugContent}`, { cause: debugParams }) }
内容的提问来源于stack exchange,提问作者Sasgorilla
相关产品推荐
相关产品推荐

