你是否曾经在处理JSON数据时遇到过这样的场景:从服务器拿到一串数据,却发现日期变成了奇怪的字符串格式;或者想序列化一个对象,却总有些属性莫名其妙地丢失了?
别担心,今天我就来分享JSON数据处理中最实用的4个技巧,让你从此告别这些烦恼!
基础但至关重要的两个方法
先来说说最基础的JSON.stringify()
和JSON.parse()
。这两个方法看似简单,但很多人其实并没有完全掌握它们的精髓。
JSON.stringify()
用于将JavaScript对象转换成JSON字符串。举个最简单的例子:
const user = {
name: '张三',
age: 25,
isAdmin: true
};
const jsonString = JSON.stringify(user);
console.log(jsonString);
而JSON.parse()
则正好相反,它把JSON字符串解析成JavaScript对象:
const jsonString = '{"name":"张三","age":25,"isAdmin":true}';
const user = JSON.parse(jsonString);
console.log(user.name);
看起来很简单对吧?但问题往往就出在这些基础操作上。比如当你尝试序列化包含函数、undefined或者循环引用的对象时,就会遇到各种意外情况。
第二个参数的妙用
很多人不知道,JSON.stringify()
和JSON.parse()
都支持第二个参数,这个参数能帮你解决很多实际问题。
在JSON.stringify()
中,第二个参数叫做replacer
,它可以是一个函数或者数组,用来控制哪些属性应该被序列化。
比如你有一个用户对象,但不想序列化密码字段:
const user = {
name: '张三',
age: 25,
password: '123456'
};
const jsonString = JSON.stringify(user, (key, value) => {
if (key === 'password') {
return undefined;
}
return value;
});
console.log(jsonString);
你也可以直接传递一个包含需要序列化的属性名的数组:
const jsonString = JSON.stringify(user, ['name', 'age']);
console.log(jsonString);
处理日期对象的经典问题
这是实际开发中最常见的问题之一。JavaScript的Date对象在序列化后会变成ISO格式的字符串,但反序列化时却不会自动转换回Date对象。
const data = {
name: '事件记录',
createdAt: new Date()
};
const jsonString = JSON.stringify(data);
console.log(jsonString);
const parsedData = JSON.parse(jsonString);
console.log(typeof parsedData.createdAt);
这时候就需要用到JSON.parse()
的第二个参数reviver
函数了:
const parsedData = JSON.parse(jsonString, (key, value) => {
if (typeof value === 'string' &&
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) {
return new Date(value);
}
return value;
});
console.log(typeof parsedData.createdAt);
console.log(parsedData.createdAt instanceof Date);
这个技巧在实际项目中特别有用,特别是当你需要处理来自API的包含日期字段的数据时。
自定义序列化行为:toJSON方法
有时候,你可能想对某个对象的序列化过程有更精细的控制。这时候可以实现toJSON
方法。
当JSON.stringify()
遇到一个对象有toJSON
方法时,它会调用这个方法并使用其返回值进行序列化。
class User {
constructor(name, age, password) {
this.name = name;
this.age = age;
this.password = password;
}
toJSON() {
return {
name: this.name,
age: this.age,
isAdult: this.age >= 18
};
}
}
const user = new User('李四', 20, 'secret');
const jsonString = JSON.stringify(user);
console.log(jsonString);
这种方法特别适合当你需要为特定类定义统一的序列化规则时。
实际应用场景
让我们来看一个综合应用的例子。假设我们正在开发一个任务管理系统:
class Task {
constructor(title, dueDate) {
this.title = title;
this.dueDate = dueDate;
this.createdAt = new Date();
this.isCompleted = false;
}
complete() {
this.isCompleted = true;
}
toJSON() {
return {
title: this.title,
dueDate: this.dueDate,
createdAt: this.createdAt,
isCompleted: this.isCompleted,
isOverdue: !this.isCompleted && this.dueDate < new Date()
};
}
}
const task = new Task('完成项目报告', new Date('2023-10-10'));
const replacer = (key, value) => {
if (value instanceof Date) {
return value.toISOString();
}
return value;
};
const taskJson = JSON.stringify(task, replacer);
console.log(taskJson);
const reviver = (key, value) => {
if (typeof value === 'string' &&
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) {
return new Date(value);
}
return value;
};
const parsedTask = JSON.parse(taskJson, reviver);
console.log(parsedTask.dueDate instanceof Date);
避免常见陷阱
在使用这些技巧时,有几点需要特别注意:
性能考虑:replacer
和reviver
函数会对每个属性执行,在处理大型对象时可能影响性能。只在必要时使用它们。
错误处理:JSON.parse()
在遇到无效JSON时会抛出异常,记得用try-catch包装:
try {
const data = JSON.parse(invalidJsonString);
} catch (error) {
console.error('解析JSON失败:', error);
}
安全性:永远不要直接解析来自不可信源的JSON数据,这可能带来安全风险。始终验证和清理输入数据。
转自https://juejin.cn/post/7545758149861736500
该文章在 2025/9/8 8:55:48 编辑过