JSON

Baseline 广泛可用 *

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

* 此特性的某些部分可能存在不同级别的支持。

JSON 命名空间对象包含用于解析 JavaScript 对象表示法 (JSON) (JSON) 中的值以及将值转换为 JSON 的静态方法。

描述

与大多数全局对象不同,JSON 不是构造函数。您不能将其与 new 运算符 一起使用,也不能将 JSON 对象调用为函数。JSON 的所有属性和方法都是静态的(就像 Math 对象一样)。

JavaScript 和 JSON 的区别

JSON 是一种用于序列化对象、数组、数字、字符串、布尔值和 null 的语法。它基于 JavaScript 语法,但与 JavaScript 不同:大多数 JavaScript 不是 JSON。例如:

对象和数组

属性名必须是双引号括起来的字符串;尾部逗号 是禁止的。

数字

禁止前导零。小数点后必须至少跟一个数字。NaNInfinity 不受支持。

任何 JSON 文本在 JSON 超集修订之后都是有效的 JavaScript 表达式。在此修订之前,U+2028 LINE SEPARATOR 和 U+2029 PARAGRAPH SEPARATOR 允许在 JSON 的字符串字面量和属性键中使用;但在 JavaScript 字符串字面量中相同的使用会导致 SyntaxError

其他区别包括只允许双引号括起来的字符串,并且不支持 undefined 或注释。对于那些希望使用更易于人类阅读的、基于 JSON 的配置格式的人来说,有 JSON5(由 Babel 编译器使用)以及更常用的 YAML

相同的文本在 JavaScript 对象字面量与 JSON 中的表示可能会有所不同。有关更多信息,请参阅 对象字面量语法与 JSON

完整的 JSON 语法

有效的 JSON 语法由以下 ABNF(扩充巴科斯-瑙尔范式)形式定义的,并从 IETF JSON 标准 (RFC) 复制而来。

JSON-text = object / array
begin-array     = ws %x5B ws  ; [ left square bracket
begin-object    = ws %x7B ws  ; { left curly bracket
end-array       = ws %x5D ws  ; ] right square bracket
end-object      = ws %x7D ws  ; } right curly bracket
name-separator  = ws %x3A ws  ; : colon
value-separator = ws %x2C ws  ; , comma
ws = *(
     %x20 /              ; Space
     %x09 /              ; Horizontal tab
     %x0A /              ; Line feed or New line
     %x0D                ; Carriage return
     )
value = false / null / true / object / array / number / string
false = %x66.61.6c.73.65   ; false
null  = %x6e.75.6c.6c      ; null
true  = %x74.72.75.65      ; true
object = begin-object [ member *( value-separator member ) ]
         end-object
member = string name-separator value
array = begin-array [ value *( value-separator value ) ] end-array
number = [ minus ] int [ frac ] [ exp ]
decimal-point = %x2E       ; .
digit1-9 = %x31-39         ; 1-9
e = %x65 / %x45            ; e E
exp = e [ minus / plus ] 1*DIGIT
frac = decimal-point 1*DIGIT
int = zero / ( digit1-9 *DIGIT )
minus = %x2D               ; -
plus = %x2B                ; +
zero = %x30                ; 0
string = quotation-mark *char quotation-mark
char = unescaped /
    escape (
        %x22 /          ; "    quotation mark  U+0022
        %x5C /          ; \    reverse solidus U+005C
        %x2F /          ; /    solidus         U+002F
        %x62 /          ; b    backspace       U+0008
        %x66 /          ; f    form feed       U+000C
        %x6E /          ; n    line feed       U+000A
        %x72 /          ; r    carriage return U+000D
        %x74 /          ; t    tab             U+0009
        %x75 4HEXDIG )  ; uXXXX                U+XXXX
escape = %x5C              ; \
quotation-mark = %x22      ; "
unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
HEXDIG = DIGIT / %x41-46 / %x61-66   ; 0-9, A-F, or a-f
       ; HEXDIG equivalent to HEXDIG rule in [RFC5234]
DIGIT = %x30-39            ; 0-9
      ; DIGIT equivalent to DIGIT rule in [RFC5234]

无意义的 空格 可以在任何地方出现,但不能出现在 JSONNumber(数字不能包含空格)或 JSONString(其中空格被解释为字符串中的相应字符,否则会导致错误)内部。制表符 (U+0009)、回车符 (U+000D)、换行符 (U+000A) 和空格 (U+0020) 是唯一有效的空格字符。

静态属性

JSON[Symbol.toStringTag]

[Symbol.toStringTag] 属性的初始值为字符串 "JSON"。此属性用于 Object.prototype.toString()

静态方法

JSON.isRawJSON()

测试一个值是否为 JSON.rawJSON() 返回的对象。

JSON.parse()

解析一段字符串文本作为 JSON,可选地转换生成的 P 值及其属性,然后返回该值。

JSON.rawJSON()

创建一个包含一段 JSON 文本的“原始 JSON”对象。序列化为 JSON 时,原始 JSON 对象被视为已经是 JSON 片段。此文本必须是有效的 JSON。

JSON.stringify()

返回与指定值对应的 JSON 字符串,可选地只包含特定属性或以用户定义的方式替换属性值。

示例

示例 JSON

json
{
  "browsers": {
    "firefox": {
      "name": "Firefox",
      "pref_url": "about:config",
      "releases": {
        "1": {
          "release_date": "2004-11-09",
          "status": "retired",
          "engine": "Gecko",
          "engine_version": "1.7"
        }
      }
    }
  }
}

您可以使用 JSON.parse() 方法将上面的 JSON 字符串转换为 JavaScript 对象。

js
const jsonText = `{
  "browsers": {
    "firefox": {
      "name": "Firefox",
      "pref_url": "about:config",
      "releases": {
        "1": {
          "release_date": "2004-11-09",
          "status": "retired",
          "engine": "Gecko",
          "engine_version": "1.7"
        }
      }
    }
  }
}`;

console.log(JSON.parse(jsonText));

无损数字序列化

JSON 可以包含任意精度的数字文字。但是,由于 JavaScript 使用具有固定精度的浮点表示,因此不可能在 JavaScript 中精确表示所有 JSON 数字。例如,在 JavaScript 中 12345678901234567890 === 12345678901234567000,因为它们具有相同的浮点表示。这意味着没有一个 JavaScript 数字能够精确对应 12345678901234567890 这个 JSON 数字。

假设您有一个数字的精确表示(通过 BigInt 或自定义库)。

js
const data = {
  // Using a BigInt here to store the exact value,
  // but it can also be a custom high-precision number library,
  // if the number might not be an integer.
  gross_gdp: 12345678901234567890n,
};

您想将其序列化,然后解析回相同的精确数字。这存在几个困难:

  • 在序列化方面,为了在 JSON 中获得一个数字,您必须将一个数字传递给 JSON.stringify,无论是通过 replacer 函数还是通过 toJSON 方法。但在任何一种情况下,您在数字转换时已经丢失了精度。如果您将字符串传递给 JSON.stringify,它将被序列化为字符串,而不是数字。
  • 在解析方面,并非所有数字都能被精确表示。例如,JSON.parse("12345678901234567890") 返回 12345678901234568000,因为该数字被四舍五入到最接近的可表示数字。即使您使用 reviver 函数,数字在调用 reviver 函数之前就已经被四舍五入了。

通常有两种方法可以确保数字被无损地转换为 JSON 并解析回来:一种涉及 JSON 数字,另一种涉及 JSON 字符串。JSON 是一个通信格式,因此如果您使用 JSON,您很可能是在与其他系统通信(HTTP 请求、存储在数据库中等)。最佳解决方案取决于接收方系统。

使用 JSON 字符串

如果接收方系统没有与 JavaScript 相同的 JSON 处理能力,并且不支持高精度数字,您可能希望将数字序列化为字符串,然后在接收方将其作为字符串处理。在旧版 JavaScript 中,这也是唯一的选项。

要指定自定义数据类型(包括 BigInt)如何序列化为 JSON,请向您的数据类型添加一个 toJSON 方法,或者使用 JSON.stringify()replacer 函数。

js
// Using toJSON() method
BigInt.prototype.toJSON = function () {
  return this.toString();
};
const str1 = JSON.stringify(data);

// Using JSON.stringify() with replacer
const str2 = JSON.stringify(data, (key, value) => {
  if (key === "gross_gdp") {
    return value.toString();
  }
  return value;
});

在这两种情况下,JSON 文本看起来都将是 {"gross_gdp":"12345678901234567890"},其中值是字符串,而不是数字。然后,在接收方,您可以解析 JSON 并处理该字符串。

使用 JSON 数字

如果消息的接收方原生支持高精度数字(例如 Python 整数),则将数字作为 JSON 数字传递显然更好,因为它们可以直接解析为高精度类型,而不是从 JSON 解析字符串,然后再从字符串解析数字。在 JavaScript 中,您可以通过使用 JSON.rawJSON() 来精确指定 JSON 源文本应该是怎样的,从而在不先产生数字值(导致精度丢失)的情况下将任意数据类型序列化为 JSON 数字。

js
// Using toJSON() method
BigInt.prototype.toJSON = function () {
  return JSON.rawJSON(this.toString());
};
const str1 = JSON.stringify(data);

// Using JSON.stringify() with replacer
const str2 = JSON.stringify(data, (key, value) => {
  if (key === "gross_gdp") {
    return JSON.rawJSON(value.toString());
  }
  return value;
});

传递给 JSON.rawJSON 的文本被视为已经是 JSON 片段,因此不会再次被序列化为字符串。因此,JSON 文本看起来将是 {"gross_gdp":12345678901234567890},其中值是数字。前提是接收方系统没有与 JavaScript 相同的精度限制,此 JSON 就可以被接收方直接解析,无需额外处理。

在 JavaScript 中解析包含高精度数字的 JSON 时,请格外小心,因为当 JSON.parse() 调用 reviver 函数时,您收到的值已经经过解析(并且已经丢失了精度)。您可以使用 JSON.parse()reviver 函数中的 context.source 参数来自己重新解析数字。

js
const parsedData = JSON.parse(str, (key, value, context) => {
  if (key === "gross_gdp") {
    // Or use the constructor of your custom high-precision number library
    return BigInt(context.source);
  }
  return value;
});
// { gross_gdp: 12345678901234567890n }

规范

规范
ECMAScript® 2026 语言规范
# sec-json-object

浏览器兼容性

另见