两边的规则差异
JavaScript 字符串字面量和 JSON 字符串长得像,规则却明显不同:JS 额外支持单引号、\xHH、\u{码点}、\0、行末续行与模板字符串,还允许「不认识的反斜杠转义直接退化为字符本身」。JSON 只认几个固定转义,任何越界写法都是语法错误。把 JS 字面量直接塞进 JSON 解析器,是配置类问题最常见的故障来源。
两边规则对照
| 引号 | JS 单/双引号均可;JSON 只能双引号 |
|---|---|
| 十六进制转义 | JS 支持 \xHH;JSON 不支持,只有 \uXXXX |
| 码点转义 | JS 支持 \u{1F600};JSON 不支持 |
| 未知转义 | JS 静默退化为该字符(\d 等于 d);JSON 报语法错误 |
| 其它 | JS 有行末续行、模板字符串 ${}、正则字面量;JSON 一概没有 |
典型使用场景
- 把前端写好的常量对象搬进 .json 配置文件,去掉单引号与注释
- 调试接口返回:判断字符串是 JSON 还是被塞进 JS 源码
- 在 JS 里安全地拼出一段 HTML 属性或 SQL 片段中的字符串常量
- 把正则写进 JSON 配置,注意反斜杠需要成对而不是 \x
- 排查「本地能跑、构建后报错」,往往是把 JS 字面量交给了严格解析器
字面量差异实测
字面量差异实测
// JS 合法,JSON 非法
const a = 'it\'s'; // 单引号 + 转义引号
const b = '\x41'; // 'A'
const c = '\u{1F600}'; // 码点形式
const d = '\d'; // 结果是 'd':未知转义退化为字符本身
const e = "a\
b"; // 行末续行,结果是 'ab'
// 用 JSON.stringify 生成可粘贴进 JSON 的字符串
JSON.stringify("C:\\tmp") // '"C:\\\\tmp"'互换时的处理方式
| 来源写法 | 目标 JSON | 处理建议 |
|---|---|---|
| 'abc' | 非法 | 改双引号,或让工具序列化 |
| \x41 | 非法 | 先按 JS 解析再序列化为 JSON |
| \u{1F600} | 非法 | 转成代理对 \uD83D\uDE00 |
| \d | 非法 | 本意是正则,JSON 里写 \\d |
| // 注释 | 非法 | 删掉注释,配置说明移到文档 |
JS 的「未知转义退化」特性很隐蔽:字符串里写 \d 不会报错,只是拿到 d。如果这段内容随后被当作正则,行为就与预期完全相反;写正则请用正则字面量或 RegExp 构造函数配双反斜杠。
2019 年起 JSON.stringify 对孤立代理做了良构化处理,会把它输出成 \uD800 这样的转义;但这只是避免输出非法文本,语义上仍是残缺字符,源头问题还得在数据侧解决。