Appearance
JavaScript JSON
什么是 JSON
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它基于 JavaScript 的对象字面量语法,但独立于 JavaScript。JSON 是一种文本格式,易于人类阅读和编写,同时也易于机器解析和生成。
JSON 的特点
- 轻量级:JSON 格式简洁,数据量小,传输速度快
- 易读易写:JSON 格式符合人类阅读习惯,易于编写和理解
- 跨语言:JSON 可以被多种编程语言解析和生成
- 基于 JavaScript:JSON 语法基于 JavaScript 对象字面量语法,但有一些差异
- 文本格式:JSON 是纯文本格式,可以通过网络传输
JSON 语法
1. 基本语法规则
- JSON 数据由键值对组成
- 键必须是字符串,用双引号包围
- 值可以是字符串、数字、布尔值、数组、对象或 null
- 键值对之间用逗号分隔
- 对象用花括号
{}包围 - 数组用方括号
[]包围
2. JSON 与 JavaScript 对象的区别
| 特性 | JSON | JavaScript 对象 |
|---|---|---|
| 键 | 必须用双引号包围 | 可以不用引号,或用单引号、双引号 |
| 值 | 不能包含函数、undefined、NaN、Infinity | 可以包含函数、undefined、NaN、Infinity |
| 字符串 | 必须用双引号包围 | 可以用单引号、双引号或反引号 |
| 末尾逗号 | 不允许 | 允许 |
| 注释 | 不允许 | 允许 |
3. JSON 示例
基本 JSON 对象
json
{
"name": "John",
"age": 30,
"isStudent": false,
"address": {
"street": "123 Main St",
"city": "New York",
"country": "USA"
},
"hobbies": ["reading", "coding", "traveling"],
"birthdate": "1993-01-01",
"score": null
}基本 JSON 数组
json
[
{
"name": "John",
"age": 30
},
{
"name": "Jane",
"age": 25
},
{
"name": "Bob",
"age": 35
}
]JSON 方法
JavaScript 提供了两个内置方法来处理 JSON:
JSON.parse():将 JSON 字符串解析为 JavaScript 对象JSON.stringify():将 JavaScript 对象序列化为 JSON 字符串
1. JSON.parse()
语法:JSON.parse(text[, reviver])
text:要解析的 JSON 字符串reviver:可选,转换结果的函数,用于修改解析过程
返回值:解析后的 JavaScript 对象
示例:
javascript
// 基本使用
var jsonString =
'{"name": "John", "age": 30, "hobbies": ["reading", "coding"]}';
var obj = JSON.parse(jsonString);
console.log(obj); // { name: "John", age: 30, hobbies: ["reading", "coding"] }
console.log(obj.name); // "John"
console.log(obj.age); // 30
console.log(obj.hobbies[0]); // "reading"
// 使用 reviver 函数
var jsonString = '{"name": "John", "age": 30, "birthdate": "1993-01-01"}';
var obj = JSON.parse(jsonString, function (key, value) {
if (key === "birthdate") {
return new Date(value);
}
return value;
});
console.log(obj.birthdate); // Date 对象
console.log(obj.birthdate.getFullYear()); // 1993
// 解析 JSON 数组
var jsonArrayString =
'[{"name": "John", "age": 30}, {"name": "Jane", "age": 25}]';
var arr = JSON.parse(jsonArrayString);
console.log(arr); // [{ name: "John", age: 30 }, { name: "Jane", age: 25 }]
console.log(arr[0].name); // "John"错误处理:
javascript
// 无效的 JSON 字符串
var invalidJson = '{"name": "John", "age": }';
try {
var obj = JSON.parse(invalidJson);
console.log(obj);
} catch (error) {
console.error('解析错误:', error.message);
// 输出: 解析错误: Unexpected end of JSON input
}
// 包含注释的 JSON(无效)
var jsonWithComments = '{
// 这是注释
"name": "John",
"age": 30
}';
try {
var obj = JSON.parse(jsonWithComments);
console.log(obj);
} catch (error) {
console.error('解析错误:', error.message);
// 输出: 解析错误: Unexpected token / in JSON at position 2
}2. JSON.stringify()
语法:JSON.stringify(value[, replacer[, space]])
value:要序列化的 JavaScript 对象replacer:可选,转换结果的函数或数组,用于过滤和转换值space:可选,控制输出的缩进格式
返回值:序列化后的 JSON 字符串
示例:
javascript
// 基本使用
var obj = {
name: "John",
age: 30,
hobbies: ["reading", "coding"],
address: {
street: "123 Main St",
city: "New York",
},
};
var jsonString = JSON.stringify(obj);
console.log(jsonString);
// 输出: {"name":"John","age":30,"hobbies":["reading","coding"],"address":{"street":"123 Main St","city":"New York"}}
// 使用 space 参数格式化输出
var prettyJson = JSON.stringify(obj, null, 2);
console.log(prettyJson);
// 输出格式化的 JSON:
// {
// "name": "John",
// "age": 30,
// "hobbies": [
// "reading",
// "coding"
// ],
// "address": {
// "street": "123 Main St",
// "city": "New York"
// }
// }
// 使用 replacer 函数
var obj = {
name: "John",
age: 30,
password: "secret123", // 敏感信息,不希望序列化
birthdate: new Date(1993, 0, 1),
};
var jsonString = JSON.stringify(
obj,
function (key, value) {
if (key === "password") {
return undefined; // 返回 undefined 会跳过该属性
}
if (key === "birthdate") {
return value.toISOString(); // 转换日期为 ISO 字符串
}
return value;
},
2
);
console.log(jsonString);
// 输出: {
// "name": "John",
// "age": 30,
// "birthdate": "1993-01-01T00:00:00.000Z"
// }
// 使用 replacer 数组
var obj = {
name: "John",
age: 30,
hobbies: ["reading", "coding"],
address: {
street: "123 Main St",
city: "New York",
},
};
// 只序列化 name 和 hobbies 属性
var jsonString = JSON.stringify(obj, ["name", "hobbies"], 2);
console.log(jsonString);
// 输出: {
// "name": "John",
// "hobbies": [
// "reading",
// "coding"
// ]
// }
// 序列化数组
var arr = [
{ name: "John", age: 30 },
{ name: "Jane", age: 25 },
];
var jsonString = JSON.stringify(arr, null, 2);
console.log(jsonString);
// 输出: [
// {
// "name": "John",
// "age": 30
// },
// {
// "name": "Jane",
// "age": 25
// }
// ]注意事项:
undefined、函数和 Symbol 会被忽略(在对象中)或转换为null(在数组中)Date对象会被转换为 ISO 字符串NaN、Infinity和-Infinity会被转换为null- 循环引用会抛出错误
javascript
// 包含 undefined、函数和 Symbol 的对象
var obj = {
name: "John",
age: undefined,
greet: function () {
console.log("Hello");
},
symbol: Symbol("test"),
};
var jsonString = JSON.stringify(obj);
console.log(jsonString);
// 输出: {"name":"John"}(undefined、函数和 Symbol 被忽略)
// 包含 Date 对象的对象
var obj = {
name: "John",
birthdate: new Date(1993, 0, 1),
};
var jsonString = JSON.stringify(obj);
console.log(jsonString);
// 输出: {"name":"John","birthdate":"1993-01-01T00:00:00.000Z"}
// 包含 NaN 和 Infinity 的对象
var obj = {
name: "John",
score: NaN,
max: Infinity,
min: -Infinity,
};
var jsonString = JSON.stringify(obj);
console.log(jsonString);
// 输出: {"name":"John","score":null,"max":null,"min":null}
// 循环引用(会抛出错误)
var obj1 = { name: "John" };
var obj2 = { name: "Jane" };
obj1.friend = obj2;
obj2.friend = obj1; // 循环引用
try {
var jsonString = JSON.stringify(obj1);
console.log(jsonString);
} catch (error) {
console.error("序列化错误:", error.message);
// 输出: 序列化错误: Converting circular structure to JSON
}JSON 的应用场景
1. 网络数据传输
JSON 是 Web 应用中最常用的数据交换格式,用于客户端和服务器之间的数据传输。
示例:使用 Fetch API 获取 JSON 数据
javascript
// 从服务器获取 JSON 数据
fetch("https://api.example.com/users")
.then((response) => response.json()) // 解析 JSON 响应
.then((data) => {
console.log(data); // 处理解析后的数据
})
.catch((error) => {
console.error("Error:", error);
});
// 向服务器发送 JSON 数据
fetch("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json", // 设置内容类型为 JSON
},
body: JSON.stringify({
// 序列化对象为 JSON 字符串
name: "John",
age: 30,
email: "john@example.com",
}),
})
.then((response) => response.json())
.then((data) => {
console.log("Success:", data);
})
.catch((error) => {
console.error("Error:", error);
});2. 本地存储
JSON 常用于本地存储,如 localStorage 和 sessionStorage,因为这些存储机制只能存储字符串。
示例:使用 localStorage 存储 JSON 数据
javascript
// 存储 JSON 数据到 localStorage
var user = {
name: "John",
age: 30,
preferences: {
theme: "dark",
notifications: true,
},
};
localStorage.setItem("user", JSON.stringify(user)); // 序列化并存储
// 从 localStorage 获取 JSON 数据
var storedUser = localStorage.getItem("user");
if (storedUser) {
var userObj = JSON.parse(storedUser); // 解析 JSON 字符串
console.log(userObj); // { name: "John", age: 30, ... }
}
// 更新存储的数据
user.age = 31;
localStorage.setItem("user", JSON.stringify(user));
// 清除存储的数据
localStorage.removeItem("user");3. 配置文件
JSON 常用于配置文件,因为它结构清晰,易于阅读和修改。
示例:配置文件
json
// config.json
{
"api": {
"baseUrl": "https://api.example.com",
"timeout": 5000,
"headers": {
"Content-Type": "application/json"
}
},
"app": {
"name": "My App",
"version": "1.0.0",
"debug": true
}
}javascript
// 加载配置文件
fetch("config.json")
.then((response) => response.json())
.then((config) => {
console.log("API Base URL:", config.api.baseUrl);
console.log("App Name:", config.app.name);
// 使用配置
});4. 数据交换
JSON 常用于不同系统之间的数据交换,因为它是一种通用格式,几乎所有编程语言都支持。
示例:Node.js 中处理 JSON
javascript
// Node.js 中读取 JSON 文件
const fs = require("fs");
// 读取 JSON 文件
const config = JSON.parse(fs.readFileSync("config.json", "utf8"));
console.log(config);
// 写入 JSON 文件
const user = {
name: "John",
age: 30,
};
fs.writeFileSync("user.json", JSON.stringify(user, null, 2));
console.log("User data written to user.json");5. 状态管理
在前端框架中,JSON 常用于状态管理,如 Redux 和 Vuex。
示例:Redux 中的状态序列化
javascript
// Redux 中保存状态到 localStorage
const saveState = (state) => {
try {
const serializedState = JSON.stringify(state);
localStorage.setItem("reduxState", serializedState);
} catch (err) {
console.error("Error saving state:", err);
}
};
// 从 localStorage 加载状态
const loadState = () => {
try {
const serializedState = localStorage.getItem("reduxState");
if (serializedState === null) {
return undefined;
}
return JSON.parse(serializedState);
} catch (err) {
console.error("Error loading state:", err);
return undefined;
}
};
// 使用
const store = createStore(
rootReducer,
loadState() // 加载保存的状态
);
// 订阅状态变化,保存到 localStorage
store.subscribe(() => {
saveState(store.getState());
});JSON 的最佳实践
1. 格式规范
- 使用双引号包围键和字符串值
- 保持缩进一致,提高可读性
- 避免使用注释(JSON 不支持)
- 确保 JSON 格式正确,特别是嵌套结构
2. 性能优化
- 对于大型 JSON 数据,考虑使用流式解析
- 避免不必要的嵌套层次,保持数据结构扁平
- 只包含必要的数据,减少数据传输量
- 使用压缩(如 gzip)减少 JSON 数据的大小
3. 安全性
- 验证 JSON 数据的来源,避免注入攻击
- 对 JSON 数据进行适当的转义,防止 XSS 攻击
- 限制 JSON 数据的大小,防止 DoS 攻击
- 对敏感信息进行加密,不要明文存储
4. 错误处理
- 使用 try-catch 捕获 JSON 解析错误
- 提供友好的错误信息,帮助用户理解问题
- 对无效的 JSON 数据进行适当的处理,避免应用崩溃
5. 兼容性
- 考虑浏览器兼容性,特别是对于较旧的浏览器
- 对于不支持 JSON 方法的浏览器,可以使用 polyfill
- 确保 JSON 数据的格式在不同语言和平台之间兼容
JSON 相关工具
1. JSON 验证工具
- JSONLint:在线验证 JSON 格式
- JSON Formatter:在线格式化和验证 JSON
- Visual Studio Code:内置 JSON 验证和格式化功能
2. JSON 处理库
- json5:扩展的 JSON 格式,支持注释和尾随逗号
- circular-json:处理循环引用的 JSON 库
- jsonschema:JSON Schema 验证库
- fast-json-stringify:高性能的 JSON 序列化库
3. 浏览器开发者工具
现代浏览器的开发者工具提供了 JSON 查看和格式化功能:
- Network 面板:查看和格式化网络请求中的 JSON 数据
- Console 面板:使用
JSON.stringify(obj, null, 2)格式化输出对象 - Application 面板:查看 localStorage 和 sessionStorage 中的 JSON 数据
常见问题及解决方案
1. JSON 解析错误
问题:JSON.parse() 抛出解析错误。
解决方案:
- 确保 JSON 格式正确,特别是键值对的语法
- 检查是否有尾随逗号、注释或其他无效字符
- 使用 JSON 验证工具验证 JSON 格式
- 使用 try-catch 捕获错误并提供友好的错误信息
2. 循环引用导致序列化失败
问题:JSON.stringify() 遇到循环引用时抛出错误。
解决方案:
- 避免对象之间的循环引用
- 使用第三方库(如 circular-json)处理循环引用
- 在序列化前手动打破循环引用
3. 大型 JSON 数据导致性能问题
问题:处理大型 JSON 数据时性能下降。
解决方案:
- 使用流式解析器处理大型 JSON 数据
- 减少 JSON 数据的大小,只包含必要的信息
- 使用压缩减少数据传输量
- 考虑使用其他数据格式,如 Protocol Buffers 或 MessagePack
4. 日期序列化问题
问题:Date 对象被序列化为字符串后,解析时不会自动转换回 Date 对象。
解决方案:
- 使用
JSON.parse()的reviver函数手动转换日期 - 在序列化前将日期转换为 ISO 字符串,解析后手动转换回
Date对象 - 使用第三方库处理日期序列化和解析
5. 敏感信息泄露
问题:JSON 数据中包含敏感信息,如密码或 API 密钥。
解决方案:
- 不要在客户端存储敏感信息
- 在序列化前过滤掉敏感信息
- 对敏感信息进行加密
- 使用 HTTPS 传输 JSON 数据
总结
JSON 是一种轻量级、易读易写的数据交换格式,它基于 JavaScript 的对象字面量语法,但独立于 JavaScript。JavaScript 提供了 JSON.parse() 和 JSON.stringify() 方法来处理 JSON 数据。
JSON 的主要应用场景包括:
- 网络数据传输
- 本地存储
- 配置文件
- 数据交换
- 状态管理
使用 JSON 时,应注意以下几点:
- 确保 JSON 格式正确
- 处理错误情况
- 优化性能
- 确保安全性
- 考虑兼容性
通过掌握 JSON 的使用方法和最佳实践,你可以更有效地在 JavaScript 应用中处理数据,提高应用的性能和可靠性。