JSON

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

¥The JSON namespace object contains static methods for parsing values from and converting values to JavaScript Object Notation (JSON).

描述

¥Description

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

¥Unlike most global objects, JSON is not a constructor. You cannot use it with the new operator or invoke the JSON object as a function. All properties and methods of JSON are static (just like the Math object).

JavaScript 和 JSON 的区别

¥JavaScript and JSON differences

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

¥JSON is a syntax for serializing objects, arrays, numbers, strings, booleans, and null. It is based upon JavaScript syntax, but is distinct from JavaScript: most of JavaScript is not JSON. For example:

对象和数组

属性名称必须是双引号字符串;尾随逗号 是禁止的。

数字

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

任何 JSON 文本都是有效的 JavaScript 表达式,但仅限于 JSON 超集 修订版之后。修订之前,JSON 中的字符串文字和属性键中允许使用 U+2028 行分隔符和 U+2029 段落分隔符;但 JavaScript 字符串文字中的相同用法是 SyntaxError

¥Any JSON text is a valid JavaScript expression, but only after the JSON superset revision. Before the revision, U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR are allowed in string literals and property keys in JSON; but the same use in JavaScript string literals is a SyntaxError.

其他差异包括仅允许双引号字符串且不支持 undefined 或注释。对于那些希望使用基于 JSON 的更人性化配置格式的人来说,有 Babel 编译器使用的 JSON5 和更常用的 YAML

¥Other differences include allowing only double-quoted strings and no support for undefined or comments. For those who wish to use a more human-friendly configuration format based on JSON, there is JSON5, used by the Babel compiler, and the more commonly used YAML.

相同的文本在 JavaScript 对象字面量和 JSON 中也可能表示不同的值。欲了解更多信息,请参阅 对象字面量语法与 JSON

¥The same text may represent different values in JavaScript object literals vs. JSON as well. For more information, see Object literal syntax vs. JSON.

完整的 JSON 语法

¥Full JSON grammar

有效的 JSON 语法由以下语法正式定义,以 ABNF 表示,并从 IETF JSON 标准 (RFC) 复制:

¥Valid JSON syntax is formally defined by the following grammar, expressed in ABNF, and copied from IETF JSON standard (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]

无关紧要的 whitespace 可以出现在除 JSONNumber(数字不得包含空格)或 JSONString(其中它被解释为字符串中的相应字符,否则会导致错误)之外的任何位置。制表符 (U+0009)、回车符 (U+000D)、换行符 (U+000A) 和空格 (U+0020) 字符是唯一有效的空白字符。

¥Insignificant whitespace may be present anywhere except within a JSONNumber (numbers must contain no whitespace) or JSONString (where it is interpreted as the corresponding character in the string, or would cause an error). The tab character (U+0009), carriage return (U+000D), line feed (U+000A), and space (U+0020) characters are the only valid whitespace characters.

静态属性

¥Static properties

JSON[@@toStringTag]

@@toStringTag 属性的初始值为字符串 "JSON"。该属性在 Object.prototype.toString() 中使用。

静态方法

¥Static methods

JSON.isRawJSON() Experimental

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

JSON.parse()

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

JSON.rawJSON() Experimental

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

JSON.stringify()

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

示例

¥Examples

JSON 示例

¥Example 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 对象:

¥You can use the JSON.parse() method to convert the above JSON string into a JavaScript object:

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));

无损数字序列化

¥Lossless number serialization

JSON 可以包含任意精度的数字文字。然而,在 JavaScript 中不可能精确地表示所有 JSON 数字,因为 JavaScript 使用具有固定精度的浮点表示。例如,JavaScript 中的 12345678901234567890 === 12345678901234567000,因为它们具有相同的浮点表示形式。这意味着没有与 12345678901234567890 JSON 数字精确对应的 JavaScript 数字。

¥JSON can contain number literals of arbitrary precision. However, it is not possible to represent all JSON numbers exactly in JavaScript, because JavaScript uses floating point representation which has a fixed precision. For example, 12345678901234567890 === 12345678901234567000 in JavaScript because they have the same floating point representation. This means there is no JavaScript number that corresponds precisely to the 12345678901234567890 JSON number.

假设你有某个数字的精确表示(通过 BigInt 或自定义库):

¥Let's assume you have a exact representation of some number (either via BigInt or a custom library):

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,
};

你想要序列化它,然后解析为相同的确切数字。有几个难点:

¥You want to serialize it and then parse to the same exact number. There are several difficulties:

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

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

¥There are, in general, two ways to ensure that numbers are losslessly converted to JSON and parsed back: one involves a JSON number, another involves a JSON string. JSON is a communication format, so if you use JSON, you are likely communicating with another system (HTTP request, storing in database, etc.). The best solution to choose depends on the recipient system.

使用 JSON 字符串

¥Using JSON strings

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

¥If the recipient system does not have same JSON-handling capabilities as JavaScript, and does not support high precision numbers, you may want to serialize the number as a string, and then handle it as a string on the recipient side. This is also the only option in older JavaScript.

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

¥To specify how custom data types (including BigInt) should be serialized to JSON, either add a toJSON method to your data type, or use the replacer function of JSON.stringify().

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 并处理该字符串。

¥In either case, the JSON text will look like {"gross_gdp":"12345678901234567890"}, where the value is a string, not a number. Then, on the recipient side, you can parse the JSON and handle the string.

使用 JSON 数字

¥Using JSON numbers

如果此消息的接收者本身支持高精度数字(例如 Python 整数),那么将数字作为 JSON 数字传递显然更好,因为他们可以直接解析为高精度类型,而不是从 JSON 解析字符串,然后解析数字 从字符串中。在 JavaScript 中,你可以通过使用 JSON.rawJSON() 精确指定 JSON 源文本应该是什么,将任意数据类型序列化为 JSON 数字,而无需先生成数字值(导致精度损失)。

¥If the recipient of this message natively supports high precision numbers (such as Python integers), passing numbers as JSON numbers is obviously better, because they can directly parse to the high precision type instead of parsing a string from JSON, and then parsing a number from the string. In JavaScript, you can serialize arbitrary data types to JSON numbers without producing a number value first (resulting in loss of precision) by using JSON.rawJSON() to precisely specify what the JSON source text should be.

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},其中值是数字。然后,接收者可以解析此 JSON,无需任何额外处理,前提是接收者系统没有与 JavaScript 相同的精度限制。

¥The text passed to JSON.rawJSON is treated as if it is already a piece of JSON, so it won't be serialized again as a string. Therefore, the JSON text will look like {"gross_gdp":12345678901234567890}, where the value is a number. This JSON can then be parsed by the recipient without any extra processing, provided that the recipient system does not have the same precision limitations as JavaScript.

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

¥When parsing JSON containing high-precision numbers in JavaScript, take extra care because when JSON.parse() invokes the reviver function, the value you receive is already parsed (and has lost precision). You can use the context.source parameter of the JSON.parse() reviver function to re-parse the number yourself.

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 }

规范

Specification
ECMAScript Language Specification
# sec-json-object

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看