开篇:无处不在的 JSON
嘿,各位前端开发者!今天我们来聊聊一个你几乎每天都在打交道的老朋友——JSON (JavaScript Object Notation)。
想想这些场景:
- 用 fetch 或 axios 从后端 API 获取数据,拿到手准备渲染页面的,是啥格式?——JSON!
- 想把用户的偏好设置(比如主题颜色)存到 localStorage 里,方便下次打开页面时恢复,对象怎么存进去?——先用 JSON.stringify() 转成字符串!
- 从 sessionStorage 里取出会话信息,准备用的时候,字符串怎么变回对象?——JSON.parse()!
没错,JSON 就像空气一样,弥漫在我们前端开发的各个角落。虽然它看起来很简单,但你真的完全理解它的角色和在 JavaScript 中的正确用法吗?别急,咱们今天就把它彻底搞明白!
到底什么是 JSON?(不仅仅是 JS 对象哦)
很多新手可能会顾名思义,认为 JSON 就是 JavaScript 对象。其实不完全是。
-
本质: JSON 是一种纯文本的、轻量级的数据交换格式。关键词:文本格式、交换。它的主要使命是方便不同系统、不同语言之间传递信息。
-
独立于语言: 虽然名字里带 "JavaScript",但它实际上是独立于任何编程语言的。Python、Java、PHP、Ruby... 几乎所有主流语言都有成熟的库来解析和生成 JSON。它就像是编程世界的“普通话”。
-
语法: 它的语法是 JavaScript 对象字面量语法的一个子集。这意味着:
- 键 (Key) 必须是双引号包裹的字符串。
- 值 (Value) 可以是:字符串(双引号)、数字、布尔值 (true/false)、数组 ([])、对象 ({}) 或 null。
- 不支持: 函数、undefined、Symbol、注释、键不加引号或用单引号等 JS 对象中可能存在的写法。
JSON 为何如此流行?(简单即是力量)
JSON 能成为事实上的数据交换标准,主要得益于:
- 对人友好: 语法简洁清晰,键值对结构,非常容易阅读和编写。调试 API 返回的数据时,一眼就能看明白。
- 对机器友好: 简单的语法规则意味着计算机解析和生成它非常高效。
- 与 JavaScript 的天然亲和力: 因为语法源自 JS 对象字面量,所以在 JavaScript 中处理 JSON 数据简直不要太方便,转换成本极低。
JSON 的核心使命:数据交换的通用语言
JSON 最最核心的用途,就是在不同的系统或服务之间传递数据,尤其是前后端通信。
想象一下这个流程:
-
前端(你的浏览器 JS)-> 后端(服务器,比如 Java):
- 你有一个 JavaScript 对象,包含了要提交的用户信息。
- 你调用 JSON.stringify() 将这个 JS 对象转换成 JSON 格式的字符串。
- 你把这个字符串放在 HTTP 请求的 Body 里,通过 fetch 或 axios 发送给后端 API。
-
后端 -> 前端:
- 后端服务器(比如用 Java 的 Jackson 或 Gson 库)接收到请求,解析请求 Body 里的 JSON 字符串,转换成相应的 Java 对象进行处理。
- 处理完毕,后端将需要返回给前端的数据(比如查询结果)从 Java 对象序列化成 JSON 格式的字符串。
- 后端将这个 JSON 字符串放在 HTTP 响应的 Body 里返回给前端。
- 前端的 JavaScript 代码收到响应。如果用 fetch,可以方便地调用 response.json() 方法。这个方法会自动读取响应体,并执行 JSON.parse(),将 JSON 字符串解析回 JavaScript 对象或数组。
- 现在,你就可以在 JS 代码里愉快地使用这个对象了!
除了前后端通信,JSON 也常用于:
- 配置文件 (.json): 很多工具和应用(包括 package.json)使用 JSON 文件存储配置。
- Web Storage: 如开头所说,配合 localStorage 和 sessionStorage 存储结构化数据。
JavaScript 的 JSON 处理“双雄”
JavaScript 提供了一个内置的全局对象 JSON,它有两个核心方法,是你处理 JSON 的左膀右臂:
1. JSON.stringify(value[, replacer[, space]]):JS 值 -> JSON 字符串
-
作用: 把 JavaScript 的值(通常是对象或数组)转换成 JSON 格式的字符串。
-
value: 你想转换的那个 JavaScript 值。
-
replacer (可选): 高级用法。可以是个函数,在序列化过程中对每个键值对进行处理;也可以是个数组,指定只包含数组中列出的那些属性。
-
space (可选): 控制输出格式,让 JSON 字符串更好看。可以是数字(代表每层缩进的空格数,最多 10),或字符串(如 '\t',用作缩进)。
-
注意点:
- 对象中的 undefined、任意函数、Symbol 值,在序列化时会被直接忽略。
- 数组中的 undefined、函数、Symbol 值会被转换成 null。
- 包含循环引用的对象(例如 a.b = a)无法序列化,会抛出 TypeError。
- Date 对象会被转换成其 toISOString() 的字符串形式。
const userProfile = {
id: 123,
name: "Alice",
isAdmin: false,
lastLogin: new Date(),
settings: { theme: "dark", notifications: undefined },
internalId: Symbol("alice"),
greet: function() { console.log("Hi!"); },
friends: [456, undefined, 789]
};
// 基本转换
const jsonString = JSON.stringify(userProfile);
console.log(jsonString);
// 输出类似(Date 和忽略项注意):
// {"id":123,"name":"Alice","isAdmin":false,"lastLogin":"2023-10-27T10:30:00.123Z","settings":{"theme":"dark"},"friends":[456,null,789]}
// 带缩进的美化输出
const prettyJson = JSON.stringify(userProfile, null, 2); // 2个空格缩进
console.log(prettyJson);
/* 输出:
{
"id": 123,
"name": "Alice",
"isAdmin": false,
"lastLogin": "2023-10-27T10:30:00.123Z", // Date 转为 ISO 字符串
"settings": {
"theme": "dark" // notifications: undefined 被忽略
},
"friends": [
456,
null, // undefined in array becomes null
789
]
// internalId (Symbol) 和 greet (Function) 被忽略
}
*/
2. JSON.parse(text[, reviver]):JSON 字符串 -> JS 值
-
作用: 把一个 JSON 格式的字符串解析成对应的 JavaScript 值(对象、数组、字符串、数字、布尔值或 null)。
-
text: 你要解析的那个 JSON 字符串。
-
reviver (可选): 高级用法。一个函数,会在解析过程中对每个键值对进行检查和转换。
-
注意点:
- 输入的字符串必须是严格有效的 JSON 格式,否则会当场抛出 SyntaxError 错误!
- 最佳实践: 始终将 JSON.parse() 调用放在 try...catch 块中,以优雅地处理可能的解析错误,避免程序崩溃。
const validJson = '{"name":"Bob","age":30,"city":"London","hobbies":["reading","music"]}';
const invalidJson = '{"name":"Charlie", age: 25}'; // age 没有双引号,无效!
// 解析有效 JSON
try {
const parsedData = JSON.parse(validJson);
console.log(parsedData.name); // Bob
console.log(parsedData.hobbies[0]); // reading
} catch (error) {
console.error("解析 JSON 失败:", error);
}
// 尝试解析无效 JSON
try {
const invalidData = JSON.parse(invalidJson);
console.log(invalidData);
} catch (error) {
console.error(`解析无效 JSON 时出错: ${error.message}`);
// 输出: 解析无效 JSON 时出错: Unexpected token a in JSON at position 19 (或类似)
}
结语:JSON,简单却重要
JSON 本身并不复杂,但它在现代 Web 开发中的地位至关重要。它是连接前端与后端、不同服务之间的桥梁,也是我们在浏览器中存储结构化数据的得力助手。
记住这两个核心操作:
- 发送或存储对象/数组时 -> JSON.stringify()
- 接收或读取 JSON 字符串时 -> JSON.parse() (配合 try...catch) 或 response.json()