JSON.rawJSON方法的作用是什么?

这篇文章发布于 2026年05月6日,星期三,16:49,归类于 JS API。 阅读 65 次, 今日 63 次 没有评论

 

在前端开发中,JSON对象的方法我们最常用的就是parsestringify,几乎每天都在和它们打交道——接口请求后用parse解析数据,提交数据前用stringify序列化对象。

但如果你最近关注JS的新特性,会发现多了一个不怎么起眼但却很实用的方法:JSON.rawJSON。

很多同学看到这个方法会一脸疑惑:stringify已经能序列化数据了,为什么还要整个rawJSON?它到底解决了什么问题?

今天我们就抛开晦涩的官方文档,用最接地气的方式,把JSON.rawJSON的作用、用法和避坑点讲明白,看完就能直接用到项目里。

JSON示意图

一、stringify的“隐形坑”

在讲rawJSON之前,我们先看一个日常开发中很容易踩的坑,也是rawJSON诞生的核心原因。

大家都知道,JavaScript里的数字都是浮点数,这就导致有些超大整数无法被精确表示。比如我们有一个超大的ID值:12345678901234567890,当我们用stringify序列化它时,会发现一个诡异的问题:

// 期望序列化出 12345678901234567890
console.log(JSON.stringify({ id: 12345678901234567890 }));
// 实际输出:{"id":12345678901234567000}

注意看,末尾的数字被自动“四舍五入”了,精度直接丢失!这不是bug,而是JavaScript浮点数的固有缺陷——它无法精确表示所有整数,当数字超过2^53时,就会出现精度偏差。

这个问题在对接后端接口时尤为常见,比如后端返回的用户ID、订单号是超大整数,前端用stringify序列化后,再传给后端,就会导致ID错误,进而出现查不到数据、订单异常等问题。

有人会说:那我把数字转成字符串不就行了?比如这样:

console.log(JSON.stringify({ id: "12345678901234567890" }));
// 输出:{"id":"12345678901234567890"}

这样确实能保留精度,但新的问题来了:后端接口期望的id是数字类型,而我们传过去的是字符串,会导致接口报错。这就陷入了一个两难境地:传数字,精度丢失;传字符串,类型不符。

而,JSON.rawJSON 就是为了解决这个“两难”而生的。

解决两难

二、JSON.rawJSON的核心作用

官方对JSON.rawJSON的定义很简单:创建一个“原始JSON对象”,当这个对象被JSON.stringify序列化时,会直接将传入的字符串作为JSON文本的一部分,不做任何转义、不做任何修改,也不会添加额外的引号。

说得更通俗一点:rawJSON就像是一个“容器”,你把一段合法的JSON文本放进去,它会告诉stringify:“这段内容你别乱动,直接原样输出就行”。

我们用刚才的超大整数案例来测试一下,就能瞬间明白它的作用:

// 传入一段表示超大整数的JSON文本(注意是字符串形式)
const rawId = JSON.rawJSON("12345678901234567890");
// 序列化包含rawJSON对象的对象
console.log(JSON.stringify({ id: rawId }));
// 输出:{"id":12345678901234567890}

完美!

完美表情包

既保留了超大整数的精度,又保证了序列化后的id是数字类型,后端接口能正常接收。

这就是rawJSON最核心的作用——让我们能“手动控制”JSON序列化的结果,解决stringify无法处理的精度丢失、类型不符等问题。

再举一个更直观的对比,帮大家分清rawJSON和普通字符串的区别:

// 普通字符串
const normalStr = "12345678901234567890";
// rawJSON对象
const rawStr = JSON.rawJSON("12345678901234567890");

// 分别序列化
console.log(JSON.stringify({ normal: normalStr })); // {"normal":"12345678901234567890"}
console.log(JSON.stringify({ raw: rawStr }));       // {"raw":12345678901234567890}

很明显:普通字符串会被stringify加上引号,变成字符串类型;而rawJSON对象会被原样输出,保持原本的JSON类型(这里是数字)。

三、rawJSON的3个关键细节

很多同学用rawJSON时会踩坑,不是因为方法本身难,而是没注意它的几个关键细节。

结合日常开发场景,我把这些细节整理出来,帮大家避坑。

避坑

细节1:传入的必须是“合法的JSON原语文本”

rawJSON的参数必须是一段合法的JSON文本,而且只能是JSON原语(数字、字符串、布尔值、null),不能是对象或数组。

如果传入的文本不合法,或者是对象/数组,会直接抛出SyntaxError错误。

// 合法:数字文本
JSON.rawJSON("123"); // 正确
// 合法:字符串文本(注意内部要加引号)
JSON.rawJSON('"hello"'); // 正确,序列化后是"hello"
// 合法:布尔值文本
JSON.rawJSON("true"); // 正确
// 非法:传入对象文本(会报错)
JSON.rawJSON('{"name":"张三"}'); // SyntaxError
// 非法:传入不合法的JSON文本(会报错)
JSON.rawJSON("123abc"); // SyntaxError

这里有个容易踩的坑:如果想序列化字符串类型的内容,传入的文本必须加上引号。

比如我们想让序列化后的结果是字符串”hello”,就必须传入'”hello”‘(外层是参数的引号,内层是JSON字符串的引号),否则会报错。

细节2:返回的是“特殊对象”,不是普通值

JSON.rawJSON返回的不是字符串,也不是数字,而是一个特殊的“原始JSON对象”。这个对象有两个特点:

  1. 它的原型是null,而且是冻结的(frozen),无法修改它的属性,也无法给它添加新属性,避免被意外篡改;
  2. 它有一个public属性rawJSON,里面存储着我们传入的原始字符串;

我们可以打印出来看看:

const raw = JSON.rawJSON("123456");
console.log(raw); // 输出:{ rawJSON: "123456" }
console.log(Object.getPrototypeOf(raw)); // null
console.log(Object.isFrozen(raw)); // true

这个特殊对象的唯一作用,就是告诉JSON.stringify:“我里面的内容要原样输出”。

除此之外,它没有其他实际用途,也不能当作普通对象使用。

细节3:配合JSON.isRawJSON判断是否为rawJSON对象

既然rawJSON返回的是特殊对象,那我们怎么判断一个值是不是rawJSON对象呢?

JS提供了对应的判断方法:JSON.isRawJSON。

这个方法很简单,传入一个值,返回布尔值,true表示是rawJSON对象,false表示不是。

const raw = JSON.rawJSON("123");
const normal = 123;

console.log(JSON.isRawJSON(raw)); // true
console.log(JSON.isRawJSON(normal)); // false
console.log(JSON.isRawJSON({})); // false

这个方法在实际开发中很实用,比如我们接收一个未知值,想判断它是不是rawJSON对象,再决定如何处理,就可以用它。

四、JSON.rawJSON的实际应用场景

讲完了细节,我们再说说rawJSON在实际开发中到底能用到哪些地方。除了前面提到的“超大整数精度保留”,还有两个高频场景。

场景1:解决超大整数、BigInt序列化问题

除了普通的超大整数,BigInt类型的序列化也是一个痛点。默认情况下,stringify无法序列化BigInt,会直接报错:

const bigNum = 12345678901234567890n;
JSON.stringify({ num: bigNum }); // Uncaught TypeError: Do not know how to serialize a BigInt

这时候,我们就可以用rawJSON来解决:
const bigNum = 12345678901234567890n;
// 将BigInt转成字符串,传入rawJSON
const rawBig = JSON.rawJSON(bigNum.toString());
// 序列化后正常输出数字类型
console.log(JSON.stringify({ num: rawBig })); // {"num":12345678901234567890}

这样既解决了BigInt无法序列化的问题,又保留了数字类型,后端接口也能正常接收。

场景2:精确控制JSON序列化格式

有时候,我们需要让JSON序列化的结果完全符合特定格式,而stringify的默认处理会不符合预期。比如,我们需要序列化一个特殊的字符串,要求它不被转义、不添加额外引号。

举个例子:后端要求我们传入一个JSON字符串,里面包含转义字符,但不需要被再次转义。如果用普通字符串,stringify会自动转义,导致格式错误:

// 期望输出:{"content":"hello\\world"}
// 普通字符串序列化
console.log(JSON.stringify({ content: "hello\\world" }));
// 实际输出:{"content":"hello\\\\world"}(多了一个转义符)

// 用rawJSON解决
const rawContent = JSON.rawJSON('"hello\\\\world"');
console.log(JSON.stringify({ content: rawContent }));
// 输出:{"content":"hello\\world"}(符合预期)

这种场景在对接一些老旧接口、或者特殊格式要求的接口时很常见,rawJSON能帮我们精准控制序列化的结果,避免格式错误。

避坑提醒:这些情况别用rawJSON

rawJSON虽然实用,但不是万能的,有些场景下使用反而会给自己添麻烦。结合我的开发经验,总结了3个“别用”的场景:

  1. 不需要精确控制序列化结果时,别用。如果只是普通的对象序列化,用stringify就足够了,rawJSON会增加不必要的代码复杂度;
  2. 传入的内容不是合法JSON原语时,别用。强行传入对象、数组或非法JSON文本,会直接报错,反而影响代码运行;
  3. 兼容性要求高的项目,慎用。rawJSON是ES2025引入的新特性,目前(2026年)Chrome、Edge等现代浏览器已经支持,但一些老旧浏览器(比如IE)、部分国产浏览器(尤其是电视端、低端设备)还不支持,需要做好兼容处理(可以用ponyfill填充)。

五、兼容性、ponyfill及结语

rawJSON方法的兼容性如下图所示:

rawJSON兼容性

ponyfill

JSON.rawJSON 和 isRawJSON 的 ponyfill可以参见这个项目:https://github.com/ungap/raw-json

最后总结

其实JSON.rawJSON的核心逻辑很简单,一句话就能概括:让JSON.stringify“原样输出”一段合法的JSON原语文本,解决精度丢失、类型不符、格式控制等问题。

我们不用把它想得太复杂,记住它的核心场景——超大整数/BigInt序列化、精确控制JSON格式,在需要的时候用它,就能解决很多开发中的“隐形坑”。

另外,提醒大家一句:rawJSON不是要替代stringify,而是对stringify的补充。大多数情况下,我们还是用stringify;只有遇到stringify解决不了的问题时,再考虑用rawJSON。

最后留一个小练习,大家可以自己动手试试:用rawJSON序列化一个布尔值true,再用stringify输出,看看结果是什么?欢迎在评论区留下你的答案~

美少女飞吻

(本篇完)

分享到:


发表评论(目前没有评论)