描述
与大多数全局对象不同,JSON 不是构造函数。您不能将其与 new 运算符 一起使用,也不能将 JSON 对象调用为函数。JSON 的所有属性和方法都是静态的(就像 Math 对象一样)。
JavaScript 和 JSON 的区别
JSON 是一种用于序列化对象、数组、数字、字符串、布尔值和 null 的语法。它基于 JavaScript 语法,但与 JavaScript 不同:大多数 JavaScript 不是 JSON。例如:
任何 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
{
"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 对象。
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 或自定义库)。
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 函数。
// 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 数字。
// 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 参数来自己重新解析数字。
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 |
浏览器兼容性
加载中…