在前端开发中,我们经常需要将 JavaScript 对象转换为字符串,以方便在网络传输、存储和日志输出等场景中使用。而 JSON.stringify 是一个常用的将 JSON 对象转换为字符串的方法,但它有个明显的缺点:如果 JSON 对象中包含循环引用,调用 JSON.stringify 方法时就会抛出 TypeError 异常。为了解决这个问题,我们可以使用 npm 包 stringify-safe。
安装 stringify-safe
可以通过 npm 安装 stringify-safe 包:
npm install stringify-safe
使用 stringify-safe
在代码中,可以按照如下方式使用 stringify-safe:
const stringify = require('stringify-safe'); const obj = { a: 'foo', b: {} }; obj.b.obj = obj; console.log(stringify(obj));
输出结果为:
{"a":"foo","b":{"obj":"[Circular]"}}
可以看到,stringify-safe 代替了 JSON.stringify,避免循环引用导致的异常,并把循环引用部分转换成了字符串 "[Circular]"。
下面让我们来详细解析 stringify-safe 的源码。
源码解析
stringify-safe 的实现原理是将 JSON.stringify 方法封装起来,通过保存已经处理过的对象的引用,避免处理循环引用时的死循环。
下面是 stringify-safe 的源码:
-- -------------------- ---- ------- -------- -------------- --------- ------- -------------- - ------ ------------------- -------------------- --------------- -------- - -------- -------------------- -------------- - --- ----- - -- --- ---- - -- -- -------------- -- ----- ------------- - -------- ----- ------ - -- --------- --- ------ ------ ---------- --- ------ ---------- --- - ------------- ------------------------------- - --- - ------ -------- ----- ------ - -- ------------- - -- - --- ------- - ------------------- -------- - -------------------- - -- - ---------------- -------- - -------------------- --------- ---- - -------------- -- ----------------------- ----- - ------------------------ ---- ------ - ---- ----------------- ------ -------- -- ---- - ----- - ------------------- ---- ------ - -
stringify 函数
stringify 函数是 stringify-safe 的入口函数,它接受四个参数:
- obj:要进行序列化的对象。
- replacer:可选参数,如果该参数为函数,则它为对象提供转换方法。
- spaces:可选参数,指定输出结果字符串的缩进格式。
- cycleReplacer:可选参数,当发现循环引用时的替代方法。
在函数中我们可以看到,它调用了 JSON.stringify 方法,使用 serializer 函数作为 reviver,这个函数将 JSON.stringify 方法序列化出来的字符串再进行加工。
serializer 函数
serializer 函数是 stringify-safe 最重要的函数之一,它是 JSON.stringify 方法的第二个参数 reviver,用于序列化对象的每一个属性。
该函数也接受两个参数:
- replacer:与 stringify 函数的 replacer 参数相同。
- cycleReplacer:如果出现循环引用,会使用 cycleReplacer 函数进行替代,如果未指定则默认使用内置的替代方法。
在函数中,为了解决循环引用,该函数定义了两个数组:
- stack:存储当前正在处理的对象。
- keys:存储当前正在处理对象的每个属性的键名。
在处理每个属性之前,serializer 函数会判断当前对象是否已经处理过:
- 如果正在处理的属性已经在 stack 中,则证明存在循环引用,直接调用 cycleReplacer 替换循环引用。
- 如果当前处理的对象第一次出现,则将其推入 stack 中。
最后,该函数根据 replacer 对属性的值进行处理,如果未指定 replacer,则直接返回原值。
总结
在 JavaScript 开发中,解决循环引用问题的方法有很多,而 stringify-safe 则是一种较为简单易用的解决方案,通过对 JSON.stringify 进行增强,很好地避免了循环引用导致的 TypeError 错误,并附带了 Circular 引用的处理方法。
stringify-safe 提供了一个很好的思路,如果我们需要在开发中处理其他类型的对象或数据,也可以考虑类似的封装方法,以便更好地解决问题。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/60066b5f51ab1864dac67196