掌握 JavaScript 中的 JSON:现代数据交换的基石
在现代 Web 开发中,数据交换是不可或缺的一部分。无论是客户端与服务器之间的数据传输,还是不同应用程序之间的数据共享,都需要一种高效、易读且通用的数据格式。在这里,JSON (JavaScript Object Notation) 应运而生,并迅速成为最流行的数据交换格式之一。
JSON 是一种轻量级的数据交换格式,它基于 JavaScript 编程语言的一个子集,但独立于语言。它使用人类可读的文本来表示结构化数据,使得数据传输和解析变得异常简单。JavaScript 对 JSON 提供了原生支持,使得在 JavaScript 环境中处理 JSON 数据尤为方便。
本教程将深入探讨 JSON 的基本概念、语法规则、支持的数据类型,以及如何在 JavaScript 中有效地解析 (parse) 和序列化 (stringify) JSON 数据。通过学习本教程,您将能够熟练地在 JavaScript 应用程序中利用 JSON 进行高效的数据管理和通信。
前置知识
在开始本教程之前,建议您具备以下 JavaScript 基础知识:
- 基本数据类型: 熟悉 JavaScript 中的字符串、数字、布尔值和
null。 - 对象 (Objects): 了解 JavaScript 对象的创建、属性访问和修改。
- 数组 (Arrays): 熟悉 JavaScript 数组的创建、元素访问和遍历。
目录
- JSON 简介
- 1.1 什么是 JSON?
- 1.2 为什么 JSON 如此重要?
- JSON 的语法规则
- 2.1 数据是名称/值对
- 2.2 数据通过逗号分隔
- 2.3 花括号 (
{}) 保存对象 - 2.4 方括号 (
[]) 保存数组 - 2.5 键必须是字符串 (双引号)
- JSON 支持的数据类型
- 3.1 字符串 (String)
- 3.2 数字 (Number)
- 3.3 布尔值 (Boolean)
- 3.4 Null
- 3.5 对象 (Object)
- 3.6 数组 (Array)
- 3.7 不支持的数据类型
- 在 JavaScript 中处理 JSON
- 4.1 将 JSON 字符串解析为 JavaScript 对象:
JSON.parse()- 4.1.1 基本用法
- 4.1.2 带有 reviver 函数
- 4.1.3 错误处理
- 4.2 将 JavaScript 对象序列化为 JSON 字符串:
JSON.stringify()- 4.2.1 基本用法
- 4.2.2 带有 replacer 参数
- 数组形式的 replacer
- 函数形式的 replacer
- 4.2.3 带有 space 参数
- 4.2.4
JSON.stringify()的行为和限制
- 4.1 将 JSON 字符串解析为 JavaScript 对象:
- JSON 的常见应用场景
- 5.1 Web API 数据传输
- 5.2 配置文件
- 5.3 本地存储 (LocalStorage/SessionStorage)
- JSON 与 JavaScript 对象的区别
- 总结
- 附录:术语表
1. JSON 简介
1.1 什么是 JSON?
JSON (JavaScript Object Notation),顾名思义,是“JavaScript 对象表示法”。它是一种轻量级的数据交换格式,完全独立于编程语言,但其格式灵感来源于 JavaScript 对象的字面量语法。
JSON 旨在成为一种易于人类阅读和编写,同时也易于机器解析和生成的文本格式。它通常用于服务器与 Web 应用程序之间交换数据。
核心特点:
- 轻量级: 相较于 XML 等其他数据交换格式,JSON 拥有更小的文件体积。
- 文本格式: JSON 数据是纯文本,这意味着它可以在任何程序和平台之间轻松传输。
- 自描述: JSON 的结构清晰,易于理解其数据含义。
- 语言无关: 虽然源自 JavaScript,但几乎所有主流编程语言都支持 JSON 的解析和生成。
1.2 为什么 JSON 如此重要?
在当今的 Web 开发中,JSON 扮演着至关重要的角色:
- API 数据交互: 绝大多数 RESTful API 都使用 JSON 作为请求体和响应体的数据格式。
- 配置文件: 许多现代应用程序和工具(如 Node.js 项目的
package.json)使用 JSON 来存储配置信息。 - 数据存储: 某些 NoSQL 数据库(如 MongoDB)直接使用 JSON 或其变体 BSON 来存储数据。
- 简化开发: 由于其简洁的语法和 JavaScript 的原生支持,开发者可以非常高效地处理 JSON 数据。
2. JSON 的语法规则
JSON 的语法是 JavaScript 对象字面量语法的严格子集。理解这些规则是正确使用 JSON 的前提。
2.1 数据是名称/值对
JSON 数据由一系列名称/值对 (name/value pairs) 组成。
- 名称(或称“键”)必须是字符串,并用双引号 (
") 包裹。 - 值可以是 JSON 支持的任何数据类型(字符串、数字、布尔值、
null、对象、数组)。 - 名称和值之间用冒号 (
:) 分隔。
示例:
"firstName": "John"
2.2 数据通过逗号分隔
如果一个 JSON 对象或数组包含多个名称/值对或多个元素,它们之间必须用逗号 (,) 分隔。
示例:
{
"firstName": "John",
"lastName": "Doe",
"age": 30
}
2.3 花括号 ({}) 保存对象
JSON 对象是无序的名称/值对集合。它以左花括号 ({) 开始,以右花括号 (}) 结束。
示例:
{
"name": "Alice",
"age": 25,
"isStudent": true
}
2.4 方括号 ([]) 保存数组
JSON 数组是值的有序集合。它以左方括号 ([) 开始,以右方括号 (]) 结束。数组中的值可以是 JSON 支持的任何数据类型。
示例:
[
"apple",
"banana",
"cherry"
]
数组也可以包含对象:
[
{ "name": "Item 1", "price": 10 },
{ "name": "Item 2", "price": 20 }
]
2.5 键必须是字符串 (双引号)
这是 JSON 与 JavaScript 对象字面量的一个重要区别。在 JSON 中,所有键(属性名)都必须是双引号引起来的字符串。在 JavaScript 对象中,如果键是有效的标识符,则可以不加引号或使用单引号。
JSON 中合法:
{
"name": "Bob",
"age": 40
}
JSON 中非法 (但 JavaScript 对象中合法):
// { name: "Bob" } <-- 键没有双引号
// { 'name': "Bob" } <-- 键使用单引号
3. JSON 支持的数据类型
JSON 支持以下六种数据类型的值:
3.1 字符串 (String)
- 由双引号包裹的零个或多个 Unicode 字符。
- 支持反斜杠转义序列(例如
\n、\t、\\、\")。
示例: "Hello, World!", "\"Special\" Character"
3.2 数字 (Number)
- 整型或浮点型数字。
- 不允许有前导零(除非是0本身),不允许使用八进制或十六进制表示。
- 不支持
NaN或Infinity。
示例: 10, 3.14, -5, 0
3.3 布尔值 (Boolean)
true或false。
示例: true, false
3.4 Null
- 表示空值。
示例: null
3.5 对象 (Object)
- 无序的键/值对集合,用花括号
{}包裹。
示例: {"key": "value", "anotherKey": 123}
3.6 数组 (Array)
- 有序的值集合,用方括号
[]包裹。
示例: ["apple", "banana", "orange"], [1, true, {"id": 1}]
3.7 不支持的数据类型
以下 JavaScript 数据类型不被 JSON 支持:
- 函数 (Functions)
- 日期对象 (Date objects)
undefinedSymbolBigInt
当 JavaScript 对象包含这些类型时,使用 JSON.stringify() 进行序列化时,它们会被忽略或转换为 null(例如函数或 undefined 作为对象属性值会被忽略,在数组中则会变为 null)。日期对象会被转换为 ISO 格式的字符串。
4. 在 JavaScript 中处理 JSON
JavaScript 提供了内置的 JSON 全局对象,包含了两个核心方法用于 JSON 和 JavaScript 对象之间的转换:JSON.parse() 和 JSON.stringify()。
4.1 将 JSON 字符串解析为 JavaScript 对象:JSON.parse()
JSON.parse() 方法用于将一个 JSON 格式的字符串转换为相应的 JavaScript 值或对象。
4.1.1 基本用法
const jsonString = '{"name": "Alice", "age": 30, "city": "New York"}';
const jsObject = JSON.parse(jsonString);
console.log(jsObject); // { name: 'Alice', age: 30, city: 'New York' }
console.log(jsObject.name); // Alice
console.log(typeof jsObject); // object
const jsonArrayString = '[10, 20, "hello", true]';
const jsArray = JSON.parse(jsonArrayString);
console.log(jsArray); // [10, 20, "hello", true]
console.log(jsArray[2]); // hello
4.1.2 带有 reviver 函数
JSON.parse() 可以接受第二个可选参数 reviver。reviver 是一个函数,它会遍历转换后的 JavaScript 对象的所有键值对,并在返回前对值进行修改。这在数据恢复和类型转换时非常有用(例如,将 ISO 格式的日期字符串转换为 Date 对象)。
reviver 函数的签名是 (key, value) => modifiedValue。
const jsonWithDate = '{"product": "Laptop", "price": 1200, "purchaseDate": "2023-10-26T10:00:00.000Z"}';
const data = JSON.parse(jsonWithDate, (key, value) => {
if (key === 'purchaseDate') {
return new Date(value); // 将日期字符串转换为 Date 对象
}
return value; // 保持其他值不变
});
console.log(data); // { product: 'Laptop', price: 1200, purchaseDate: Thu Oct 26 2023... }
console.log(data.purchaseDate instanceof Date); // true
4.1.3 错误处理
如果 JSON.parse() 接收到的字符串不是一个合法的 JSON 格式,它会抛出一个 SyntaxError 异常。因此,在使用时,通常建议将其放在 try...catch 块中。
const malformedJson = '{"name": "Bob", "age": 40,}'; // 尾部逗号不合法
const anotherMalformed = '{name: "Charlie"}'; // 键没有双引号
try {
JSON.parse(malformedJson);
} catch (error) {
console.error("解析错误:", error.message); // 解析错误: Unexpected token } in JSON at position 25
}
try {
JSON.parse(anotherMalformed);
} catch (error) {
console.error("解析错误:", error.message); // 解析错误: Expected property name or '}' in JSON at position 1
}
4.2 将 JavaScript 对象序列化为 JSON 字符串:JSON.stringify()
JSON.stringify() 方法用于将一个 JavaScript 值(通常是对象或数组)转换为 JSON 格式的字符串。
4.2.1 基本用法
const jsObject = {
firstName: "Jane",
lastName: "Doe",
age: 28,
hobbies: ["reading", "hiking"],
address: {
street: "123 Main St",
city: "Anytown"
}
};
const jsonString = JSON.stringify(jsObject);
console.log(jsonString);
// 输出: {"firstName":"Jane","lastName":"Doe","age":28,"hobbies":["reading","hiking"],"address":{"street":"123 Main St","city":"Anytown"}}
console.log(typeof jsonString); // string
4.2.2 带有 replacer 参数
JSON.stringify() 可以接受第二个可选参数 replacer。replacer 可以是一个数组或一个函数,用于控制哪些属性应该被包含在 JSON 字符串中,以及它们的序列化方式。
-
数组形式的
replacer:
如果replacer是一个数组,它指定了应该包含在 JSON 字符串中的属性名称。只有这些属性会被序列化。const userInfo = { name: "Alice", age: 25, email: "alice@example.com", password: "securepassword123" // 不希望序列化 }; const publicInfoJson = JSON.stringify(userInfo, ["name", "age", "email"]); console.log(publicInfoJson); // {"name":"Alice","age":25,"email":"alice@example.com"} -
函数形式的
replacer:
如果replacer是一个函数,它会为每个属性(包括父对象本身)调用。该函数接收两个参数:key(属性名) 和value(属性值)。- 如果
replacer函数返回一个值,该值将被序列化。 - 如果返回
undefined,则该属性将被从 JSON 字符串中省略。
const product = { name: "Widget", price: 100, stock: 50, manufacturer: "Acme Inc.", details: null, secretCode: "XYZ123" // 不希望序列化 }; const filteredProductJson = JSON.stringify(product, (key, value) => { if (key === 'secretCode') { return undefined; // 排除这个属性 } if (typeof value === 'string' && value.includes('Inc.')) { return value.toUpperCase(); // 修改特定字符串 } return value; }); console.log(filteredProductJson); // {"name":"Widget","price":100,"stock":50,"manufacturer":"ACME INC.","details":null} - 如果
4.2.3 带有 space 参数
JSON.stringify() 可以接受第三个可选参数 space。space 用于控制输出 JSON 字符串的缩进。它允许您使输出更具可读性。
- 如果
space是一个数字,它表示每个缩进级别的空格数量 (0-10)。 - 如果
space是一个字符串,它将作为缩进字符。
const data = { a: 1, b: { c: 2, d: 3 } };
// 不缩进 (默认)
console.log(JSON.stringify(data)); // {"a":1,"b":{"c":2,"d":3}}
// 缩进 2 个空格
console.log(JSON.stringify(data, null, 2));
/*
{
"a": 1,
"b": {
"c": 2,
"d": 3
}
}
*/
// 使用制表符缩进
console.log(JSON.stringify(data, null, '\t'));
/*
{
"a": 1,
"b": {
"c": 2,
"d": 3
}
}
*/
4.2.4 JSON.stringify() 的行为和限制
- 非对象/数组的值: 如果序列化的值不是对象或数组,它会被直接转换为 JSON 基本类型。
console.log(JSON.stringify(123)); // "123" (字符串形式的数字) console.log(JSON.stringify("hello")); // "\"hello\"" (双引号包裹的字符串) console.log(JSON.stringify(true)); // "true" console.log(JSON.stringify(null)); // "null" - 循环引用: 如果对象中存在循环引用,
JSON.stringify()会抛出TypeError: Converting circular structure to JSON。 - 特殊值处理:
undefined、函数、Symbol: 作为对象属性值时,这些属性会被跳过。作为数组元素时,它们会被转换为null。- 日期对象: 会被转换为 ISO 格式的字符串。
BigInt: 会抛出TypeError。
5. JSON 的常见应用场景
5.1 Web API 数据传输
这是 JSON 最常见的用途。当 Web 浏览器(客户端)请求服务器(例如通过 fetch 或 XMLHttpRequest)数据时,服务器通常会以 JSON 格式返回数据。客户端接收到 JSON 字符串后,使用 JSON.parse() 将其转换为 JavaScript 对象进行处理。反之,当客户端向服务器发送数据时,也会将 JavaScript 对象转换为 JSON 字符串 (JSON.stringify()) 发送。
// 客户端发送数据
const userData = { name: "John", age: 30 };
fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(userData) // 将 JS 对象转换为 JSON 字符串发送
})
.then(response => response.json()) // 接收 JSON 响应并解析
.then(data => console.log('Server response:', data))
.catch(error => console.error('Error:', error));
5.2 配置文件
许多现代工具和项目使用 JSON 文件来存储配置信息,因为其结构清晰且易于解析。例如,Node.js 项目中的 package.json 文件、VS Code 的 .vscode/settings.json 等。
// package.json 示例
{
"name": "my-app",
"version": "1.0.0",
"description": "A simple Node.js application",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Your Name",
"license": "ISC",
"dependencies": {
"express": "^4.17.1"
},
"devDependencies": {
"nodemon": "^2.0.7"
}
}
5.3 本地存储 (LocalStorage/SessionStorage)
浏览器提供的 localStorage 和 sessionStorage 只能存储字符串。因此,当需要存储 JavaScript 对象或数组时,必须先使用 JSON.stringify() 将其转换为 JSON 字符串,然后在读取时使用 JSON.parse() 转换回来。
const userSettings = {
theme: "dark",
fontSize: 16,
notifications: true
};
// 存储对象
localStorage.setItem('userSettings', JSON.stringify(userSettings));
console.log('存储成功');
// 读取对象
const storedSettingsString = localStorage.getItem('userSettings');
const loadedSettings = JSON.parse(storedSettingsString);
console.log('加载的设置:', loadedSettings); // { theme: 'dark', fontSize: 16, notifications: true }
6. JSON 与 JavaScript 对象的区别
尽管 JSON 的语法来源于 JavaScript 对象字面量,但两者之间存在一些关键区别:
| 特征 | JSON | JavaScript 对象 |
|---|---|---|
| 用途 | 数据交换格式,独立于语言 | JavaScript 语言内部的数据结构 |
| 键 (Keys) | 必须是双引号包裹的字符串 ("key") |
可以是字符串 (单引号/双引号/无引号) |
| 值 (Values) | 仅限于字符串、数字、布尔、null、对象、数组 |
除了 JSON 支持的类型,还可以是函数、undefined、Date、Symbol、BigInt 等 |
| 语法 | 严格,不允许逗号、注释等额外字符 | 相对宽松,允许尾部逗号、单引号、注释等 |
| 表现形式 | 总是字符串 | 内存中的一个数据结构 |
理解这些区别对于避免在处理 JSON 和 JavaScript 对象时产生混淆至关重要。
7. 总结
本教程对 JavaScript 中的 JSON 进行了全面深入的讲解,您现在应该掌握了:
- JSON 的本质: 了解 JSON 是一种轻量级、自描述、语言无关的数据交换格式。
- JSON 的严格语法: 掌握名称/值对、花括号、方括号和双引号包裹键的规则。
- JSON 支持的数据类型: 明确哪些 JavaScript 数据类型可以安全地在 JSON 中表示。
- 核心转换方法: 熟练使用
JSON.parse()将 JSON 字符串转换为 JavaScript 对象,以及JSON.stringify()将 JavaScript 对象转换为 JSON 字符串。 - 高级用法: 了解
reviver、replacer和space参数如何提供更精细的控制。 - 常见应用场景: 理解 JSON 在 Web API、配置文件和本地存储中的实际应用。
- 与 JavaScript 对象的区别: 明确 JSON 和 JavaScript 对象之间的语法和类型限制。
JSON 是现代 Web 开发的基石,熟练运用它将极大地提高您处理数据和构建应用程序的能力。
8. 附录:术语表
- JSON (JavaScript Object Notation): 一种轻量级、人类可读、易于机器解析的数据交换格式。
- 名称/值对 (Name/Value Pair): JSON 数据的基本单元,由一个字符串键和一个值组成,形如
"key": value。 - JSON 对象 (JSON Object): 用花括号
{}包裹的无序的名称/值对集合。 - JSON 数组 (JSON Array): 用方括号
[]包裹的有序值集合。 JSON.parse(): JavaScript 内置方法,将 JSON 格式的字符串转换为 JavaScript 值或对象。reviver函数:JSON.parse()的可选第二个参数,一个回调函数,用于在解析过程中对值进行自定义转换。JSON.stringify(): JavaScript 内置方法,将 JavaScript 值或对象转换为 JSON 格式的字符串。replacer参数:JSON.stringify()的可选第二个参数,可以是一个数组或函数,用于过滤或修改将被序列化的属性。space参数:JSON.stringify()的可选第三个参数,用于指定 JSON 输出字符串的缩进格式,以提高可读性。- 序列化 (Serialization): 将数据结构或对象状态转换为可以存储或传输的格式(通常是字符串)的过程。
- 反序列化 (Deserialization) / 解析 (Parsing): 将序列化后的数据(字符串)转换回原始数据结构或对象的过程。
- 回调地狱 (Callback Hell): 指深层嵌套的回调函数导致代码难以阅读、维护和调试的问题。
- RESTful API: 一种网络应用程序接口设计风格,通常使用 HTTP 请求来获取或修改数据,并常以 JSON 格式交换数据。
- LocalStorage/SessionStorage: 浏览器提供的 Web 存储 API,允许 Web 应用程序在客户端本地存储数据,但只能存储字符串。
更多推荐


所有评论(0)