JSON.stringify()(长文讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
前言
在 JavaScript 开发中,数据的格式转换是一个高频需求。无论是与后端 API 交互,还是在浏览器与服务器之间传输数据,开发者常常需要将 JavaScript 对象转换为字符串格式。此时,JSON.stringify()
就扮演了至关重要的角色。它不仅是开发者工具箱中的核心工具,更是理解数据序列化概念的入门钥匙。本文将从基础到进阶,结合案例与代码示例,深入解析 JSON.stringify()
的原理、用法及常见问题。
一、什么是 JSON.stringify()?
1.1 序列化与反序列化的概念
在编程中,序列化(Serialization)是指将数据结构或对象转换为可以存储或传输的格式,例如字符串或二进制数据;而反序列化(Deserialization)则是将序列化后的数据还原为原始对象。
JSON.stringify()
的作用,正是将 JavaScript 对象(Object)序列化为符合 JSON 标准的字符串。例如:
const user = { name: "Alice", age: 25 };
const serializedUser = JSON.stringify(user);
console.log(serializedUser); // 输出:{"name":"Alice","age":25}
通过这一过程,原本复杂的对象可以被转化为可在网络中高效传输的纯文本数据。
1.2 与 JSON.parse() 的对比
JSON.stringify()
的“逆操作”是 JSON.parse()
,后者将 JSON 字符串解析为 JavaScript 对象。两者的搭配使用,构成了数据序列化与反序列化的完整流程:
const jsonStr = '{"city":"Shanghai", "population":24150000}';
const cityData = JSON.parse(jsonStr);
console.log(cityData.city); // 输出:Shanghai
理解这对函数的协作关系,是掌握数据转换的关键。
二、JSON.stringify() 的基础用法
2.1 基础语法与简单示例
JSON.stringify()
的基本语法为:
JSON.stringify(value, replacer?, space?);
其中:
value
:必选参数,表示要序列化的 JavaScript 对象、数组或值。replacer
:可选参数,用于过滤或转换序列化后的数据。space
:可选参数,控制缩进和空格,使输出更易读。
示例 1:序列化对象
const person = {
name: "Bob",
hobbies: ["reading", "coding"],
isDeveloper: true
};
const jsonPerson = JSON.stringify(person);
console.log(jsonPerson);
// 输出:{"name":"Bob","hobbies":["reading","coding"],"isDeveloper":true}
示例 2:序列化嵌套对象与数组
const team = {
leader: "Charlie",
members: [
{ name: "David", role: "Designer" },
{ name: "Eve", role: "Engineer" }
]
};
console.log(JSON.stringify(team));
// 输出:{"leader":"Charlie","members":[{"name":"David","role":"Designer"},{"name":"Eve","role":"Engineer"}]}
2.2 支持的数据类型与限制
JSON.stringify()
可序列化的数据类型包括:
- 布尔值(
true
/false
) - 数值(数字类型)
- 字符串
null
- 对象(Object)与数组(Array)
不支持的数据类型:
- 函数
undefined
Symbol
(ES6 新增类型)
示例:排除不支持的类型
const invalidData = {
func: () => "Hello",
undef: undefined,
sym: Symbol("id")
};
console.log(JSON.stringify(invalidData));
// 输出:{}
// 函数、undefined、Symbol 均被忽略
三、深入参数:replacer 与 space
3.1 参数 replacer
:过滤与转换数据
replacer
可以是:
- 函数:用于自定义序列化逻辑,例如修改键值对或排除某些属性。
- 数组:用于仅保留指定的键。
案例 1:使用数组参数筛选字段
const userData = {
id: 101,
username: "Alice",
password: "secret",
email: "alice@example.com"
};
// 只保留 username 和 email
const filteredUser = JSON.stringify(userData, ["username", "email"]);
console.log(filteredUser);
// 输出:{"username":"Alice","email":"alice@example.com"}
案例 2:使用函数参数修改数据
const priceData = {
price: 99.99,
discount: 0.15
};
// 计算折扣后价格并保留两位小数
const replacerFunction = (key, value) => {
if (key === "finalPrice") {
return value; // 保留计算后的 finalPrice
}
if (key === "price") {
return value * (1 - priceData.discount); // 应用折扣
}
return value; // 其他字段保持原样
};
// 手动添加 finalPrice 属性
priceData.finalPrice = priceData.price * (1 - priceData.discount);
const modifiedJson = JSON.stringify(priceData, replacerFunction);
console.log(modifiedJson);
// 输出:{"price":84.993,"discount":0.15,"finalPrice":84.993}
3.2 参数 space
:美化输出格式
space
参数可以是:
- 数字:表示缩进空格的数量。
- 字符串:如
" "
或"\t"
,用于自定义缩进。
示例:美化 JSON 输出
const config = {
server: {
host: "localhost",
port: 3000,
timeout: 5000
},
logging: {
level: "debug"
}
};
console.log(JSON.stringify(config, null, 2));
// 输出:
// {
// "server": {
// "host": "localhost",
// "port": 3000,
// "timeout": 5000
// },
// "logging": {
// "level": "debug"
// }
// }
四、高级用法与常见场景
4.1 处理循环引用(Circular References)
当对象之间存在循环引用时,JSON.stringify()
会抛出错误。例如:
const a = { name: "Node A" };
const b = { name: "Node B", parent: a };
a.child = b; // 形成循环:a → b → a
try {
JSON.stringify(a); // 抛出错误:Converting circular structure to JSON
} catch (e) {
console.error(e.message);
}
解决方案:在 replacer
函数中检测并跳过循环引用。
function replacer(key, value) {
// 检测当前值是否为原始对象(避免无限循环)
if (value === a || value === b) {
return `{Circular Reference}`; // 替换为占位符或简化表示
}
return value;
}
const safeJson = JSON.stringify(a, replacer);
console.log(safeJson);
// 输出:{"name":"Node A","child":"{Circular Reference}"}
4.2 自定义对象的序列化逻辑
如果对象的原型链上有 toJSON()
方法,JSON.stringify()
会优先调用该方法返回序列化后的值。
class User {
constructor(name, email) {
this.name = name;
this.email = email;
this._private = "hidden"; // 私有属性
}
// 自定义序列化逻辑
toJSON() {
return {
publicName: this.name,
contact: this.email
};
}
}
const userInstance = new User("Frank", "frank@example.com");
console.log(JSON.stringify(userInstance));
// 输出:{"publicName":"Frank","contact":"frank@example.com"}
// 私有属性 _private 被自动过滤
4.3 与 API 交互的典型场景
在前端开发中,JSON.stringify()
经常用于将表单数据转换为 JSON 字符串,以便通过 fetch
或 axios
发送到后端:
const form = document.querySelector("form");
form.addEventListener("submit", (e) => {
e.preventDefault();
const formData = new FormData(form);
// 将 FormData 转换为对象
const dataObj = Object.fromEntries(formData.entries());
// 序列化并发送
fetch("/api/submit", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(dataObj)
});
});
五、常见问题与解决方案
5.1 序列化后丢失对象方法
由于 JSON 标准不支持函数类型,对象的方法会被自动忽略。例如:
const objWithMethod = {
greeting: "Hello",
sayHello() {
return this.greeting;
}
};
console.log(JSON.stringify(objWithMethod));
// 输出:{"greeting":"Hello"}
// 方法 sayHello 被移除
解决方案:如果需要传输函数逻辑,可考虑使用字符串化的代码片段,但需注意安全性风险。
5.2 处理日期对象的序列化
默认情况下,日期对象会被转换为 ISO 格式的字符串:
const date = new Date();
console.log(JSON.stringify(date));
// 输出:"2023-10-05T08:00:00.000Z"
如果需要自定义日期格式,可通过 replacer
函数实现:
function dateReplacer(key, value) {
if (value instanceof Date) {
return value.toLocaleDateString(); // 转换为本地日期格式
}
return value;
}
const customDateJson = JSON.stringify({ birthdate: new Date() }, dateReplacer);
// 输出:{"birthdate":"10/5/2023"}
5.3 性能优化建议
对于大型对象的序列化,建议:
- 使用
replacer
过滤不必要的字段,减少数据量。 - 避免在循环中频繁调用
JSON.stringify()
,可先缓存结果。 - 对于超大数据,考虑分块处理或采用二进制格式(如 MessagePack)。
六、总结
JSON.stringify()
是 JavaScript 开发中不可或缺的工具,它简化了数据序列化的复杂性,让开发者能够专注于业务逻辑的实现。通过本文的讲解,读者可以掌握以下核心要点:
- 理解序列化与反序列化的基础概念
- 掌握
JSON.stringify()
的基本语法与参数用法 - 学会处理循环引用、自定义对象及日期等特殊场景
- 避免常见陷阱并优化性能
在实际开发中,合理使用 JSON.stringify()
可以显著提升数据交互的效率与代码的可维护性。无论是构建前端表单、与 REST API 通信,还是在跨平台应用中共享数据,它都是开发者手中一把灵活的瑞士军刀。
通过本文的学习,相信读者已经能够自信地运用 JSON.stringify()
解决实际问题。记住,实践是掌握技术的最佳途径——不妨尝试将本文的案例复制到代码编辑器中运行,观察不同参数对结果的影响,逐步深化理解。