网站首页 > 技术文章 正文
JSON.stringify() 是 JavaScript 开发中最常用的方法之一,但大多数开发者只停留在基础的数据序列化使用层面。
实际上,这个方法隐藏了许多强大而实用的功能,能够解决开发中的各种实际问题。本文将深入探讨 JSON.stringify() 的进阶用法,帮助你写出更优雅、高效的代码。
一、基础回顾:JSON.stringify() 的核心机制
在深入高级用法前,我们先明确 JSON.stringify() 的基本行为:
const user = {
name: "web前端开发官网",
score: 89,
secret: undefined,
[Symbol('id')]: 123
};
console.log(JSON.stringify(user));
// 输出: '{"name":"web前端开发官网","score":89}'
关键特性:
- 自动忽略 undefined、Symbol 和函数类型的属性
- 只序列化对象自身的可枚举属性
- 日期对象会被转换为 ISO 格式字符串
- 循环引用会抛出错误
二、选择性序列化:第二个参数的妙用
1. 白名单过滤:精确控制输出字段
通过数组参数可以指定需要包含的属性列表:
const product = {
id: 101,
name: "无线耳机",
price: 299,
stock: 50,
manufacturer: "Acme Corp"
};
// 只保留 id 和 name 字段
console.log(JSON.stringify(product, ['id', 'name']));
// 输出: '{"id":101,"name":"无线耳机"}'
实际应用场景:
- api 响应数据瘦身
- 敏感信息过滤
- 减少网络传输量
2. 转换函数:动态处理每个属性
更强大的方式是使用转换函数,它可以递归处理每个属性:
const employee = {
name: "张三",
salary: 15000,
department: "研发部",
joinDate: newDate('2020-06-15')
};
const result = JSON.stringify(employee, (key, value) => {
if (key === 'salary') returnundefined; // 隐藏薪资
if (value instanceofDate) return value.toLocaleDateString();
return value;
});
console.log(result);
// 输出: '{"name":"张三","department":"研发部","joinDate":"2020/6/15"}'
高级技巧:
- 实现自定义的序列化逻辑
- 数据脱敏处理
- 特殊类型(如 BigInt)的转换
三、美化输出:第三个参数的艺术
1. 数字缩进:标准格式化
const book = {
title: "JavaScript高级程序设计",
author: {
name: "Nicholas C. Zakas",
country: "美国"
},
tags: ["前端", "编程", "ES6"]
};
console.log(JSON.stringify(book, null, 2));
输出效果:
{
"title": "JavaScript高级程序设计",
"author": {
"name": "Nicholas C. Zakas",
"country": "美国"
},
"tags": [
"前端",
"编程",
"ES6"
]
}
2. 自定义缩进:个性展示
console.log(JSON.stringify(book, null, '-->'));
输出效果:
{
-->"title": "JavaScript高级程序设计",
-->"author": {
--->"name": "Nicholas C. Zakas",
--->"country": "美国"
-->},
-->"tags": [
--->"前端",
--->"编程",
--->"ES6"
-->]
}
实用价值:
- 调试时更易读的输出
- 生成文档中的示例数据
- 保持团队代码风格统一
四、深度比较:对象指纹技术
1. 对象比较的痛点
const obj1 = { a: 1, b: 2, 1: "x" };
const obj2 = { b: 2, a: 1, 1: "x" };
console.log(JSON.stringify(obj1) === JSON.stringify(obj2)); // false
2. 键序问题的本质
JavaScript 对象键的顺序遵循特定规则:
- 数字键:按数值升序排列(0~2^3^2-1)
- 字符串键:按创建顺序排列
- Symbol键:不参与序列化
解决方案:
functionstableStringify(obj) {
returnJSON.stringify(obj, Object.keys(obj).sort());
}
console.log(stableStringify(obj1) === stableStringify(obj2)); // true
应用场景:
- 对象内容比对
- 生成唯一缓存键
- 数据一致性校验
五、特殊场景处理技巧
1. 处理循环引用
const circularObj = { a: 1 };
circularObj.self = circularObj;
// 直接序列化会报错
// JSON.stringify(circularObj); // TypeError
// 解决方案
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key, value) => {
if (typeofvalue === "object" && value !== null) {
if (seen.has(value)) return'[Circular]';
seen.add(value);
}
returnvalue;
};
};
console.log(JSON.stringify(circularObj, getCircularReplacer()));
// 输出: {"a":1,"self":"[Circular]"}
2. 自定义 toJSON 方法
classPerson{
constructor(name, age) {
this.name = name;
this.age = age;
}
toJSON() {
return {
fullName: `Mr./Ms. ${this.name}`,
birthYear: newDate().getFullYear() - this.age
};
}
}
const p = new Person("李四", 30);
console.log(JSON.stringify(p));
// 输出: {"fullName":"Mr./Ms. 李四","birthYear":1993}
六、性能与安全考量
1. 性能优化
// 不好的做法:频繁序列化大对象
for (let i = 0; i < 1000; i++) {
localStorage.setItem('data', JSON.stringify(largeObj));
}
// 优化方案:只序列化变化部分
let lastState;
functionsavePartial(state) {
const changes = {};
for (const key in state) {
if (state[key] !== lastState?.[key]) {
changes[key] = state[key];
}
}
localStorage.setItem('changes', JSON.stringify(changes));
lastState = {...state};
}
2. 安全注意事项
// 潜在XSS风险
const userInput = '{"__proto__": {"isAdmin": true}}';
const parsed = JSON.parse(userInput);
Object.assign({}, parsed); // 污染原型链
// 安全做法
const safeParse = (json) => {
const parsed = JSON.parse(json);
if (parsed && typeof parsed === 'object') {
Object.setPrototypeOf(parsed, null);
}
return parsed;
};
七、实际应用案例
1. 深度克隆的局限与改进
// 基础深克隆
functiondeepClone(obj) {
returnJSON.parse(JSON.stringify(obj));
}
// 增强版(处理特殊类型)
functionenhancedDeepClone(obj) {
returnJSON.parse(JSON.stringify(obj, (key, value) => {
if (typeof value === 'bigint') return value.toString() + 'n';
if (value instanceofRegExp) return value.toString();
return value;
}));
}
2. 数据差异比较
functiongetObjectDiff(a, b) {
const stableA = stableStringify(a);
const stableB = stableStringify(b);
if (stableA === stableB) returnnull;
// 实际项目中可以使用更专业的diff算法
return {
before: JSON.parse(stableA),
after: JSON.parse(stableB)
};
}
结语
JSON.stringify() 远不止是一个简单的序列化工具,通过掌握它的高级用法,你可以:
- 更精准地控制数据输出
- 实现复杂对象的比较和克隆
- 提升调试和日志记录效率
- 处理各种边界情况和特殊需求
记住这些技巧,它们将在以下场景中发挥巨大价值:
- API 开发与数据处理
- 状态管理与持久化
- 性能优化与调试
- 安全数据处理
希望本文能帮助你重新认识这个看似简单却功能强大的方法,在实际开发中发挥它的最大潜力。
最后,感谢你的阅读,祝编程愉快
猜你喜欢
- 2025-10-19 Python常用标准库(pickle序列化和JSON序列化)
- 2025-10-19 Linux json-c使用_linux解析json数据
- 2025-10-19 源码推荐(03.04):微信支付的测试,Json数据解析
- 2025-10-19 打开JSON文件的六种方法,总有一种适合你
- 2025-10-19 springmvc项目中接收Android提交json数据
- 2025-10-19 一篇文章让你详细了解何为JSON_json到底是什么
- 2025-10-19 FlinkSQL处理复杂JSON的思路_flinksql解析json数组
- 2025-10-19 超级好用的轻量级JSON处理命令jq_json使用教程
- 2025-10-19 .NET性能系列文章二:Newtonsoft.Json vs System.Text.Json
- 2025-10-19 推荐几个开发必备的JSON工具_推荐几个开发必备的json工具
你 发表评论:
欢迎- 最近发表
-
- Python常用标准库(pickle序列化和JSON序列化)
- Linux json-c使用_linux解析json数据
- 源码推荐(03.04):微信支付的测试,Json数据解析
- 打开JSON文件的六种方法,总有一种适合你
- springmvc项目中接收Android提交json数据
- 一篇文章让你详细了解何为JSON_json到底是什么
- FlinkSQL处理复杂JSON的思路_flinksql解析json数组
- 超级好用的轻量级JSON处理命令jq_json使用教程
- .NET性能系列文章二:Newtonsoft.Json vs System.Text.Json
- 推荐几个开发必备的JSON工具_推荐几个开发必备的json工具
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端路由 (61)
- 前端数组 (73)
- 前端js面试题 (50)
- 前端定时器 (59)
- Oracle RAC (76)
- oracle恢复 (77)
- oracle 删除表 (52)
- oracle 用户名 (80)
- oracle 工具 (55)
- oracle 内存 (55)
- oracle 导出表 (62)
- oracle约束 (54)
- oracle 中文 (51)
- oracle链接 (54)
- oracle的函数 (58)
- oracle面试 (55)
- 前端调试 (52)
本文暂时没有评论,来添加一个吧(●'◡'●)