你是否曾經(jīng)在處理JSON數(shù)據(jù)時遇到過這樣的場景:從服務(wù)器拿到一串?dāng)?shù)據(jù),卻發(fā)現(xiàn)日期變成了奇怪的字符串格式;或者想序列化一個對象,卻總有些屬性莫名其妙地丟失了?
別擔(dān)心,今天我就來分享JSON數(shù)據(jù)處理中最實用的4個技巧,讓你從此告別這些煩惱!
基礎(chǔ)但至關(guān)重要的兩個方法
先來說說最基礎(chǔ)的JSON.stringify()
和JSON.parse()
。這兩個方法看似簡單,但很多人其實并沒有完全掌握它們的精髓。
JSON.stringify()
用于將JavaScript對象轉(zhuǎn)換成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);
看起來很簡單對吧?但問題往往就出在這些基礎(chǔ)操作上。比如當(dāng)你嘗試序列化包含函數(shù)、undefined或者循環(huán)引用的對象時,就會遇到各種意外情況。
第二個參數(shù)的妙用
很多人不知道,JSON.stringify()
和JSON.parse()
都支持第二個參數(shù),這個參數(shù)能幫你解決很多實際問題。
在JSON.stringify()
中,第二個參數(shù)叫做replacer
,它可以是一個函數(shù)或者數(shù)組,用來控制哪些屬性應(yīng)該被序列化。
比如你有一個用戶對象,但不想序列化密碼字段:
const user = {
name: '張三',
age: 25,
password: '123456'
};
const jsonString = JSON.stringify(user, (key, value) => {
if (key === 'password') {
return undefined;
}
return value;
});
console.log(jsonString);
你也可以直接傳遞一個包含需要序列化的屬性名的數(shù)組:
const jsonString = JSON.stringify(user, ['name', 'age']);
console.log(jsonString);
處理日期對象的經(jīng)典問題
這是實際開發(fā)中最常見的問題之一。JavaScript的Date對象在序列化后會變成ISO格式的字符串,但反序列化時卻不會自動轉(zhuǎn)換回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()
的第二個參數(shù)reviver
函數(shù)了:
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);
這個技巧在實際項目中特別有用,特別是當(dāng)你需要處理來自API的包含日期字段的數(shù)據(jù)時。
自定義序列化行為:toJSON方法
有時候,你可能想對某個對象的序列化過程有更精細(xì)的控制。這時候可以實現(xiàn)toJSON
方法。
當(dāng)JSON.stringify()
遇到一個對象有toJSON
方法時,它會調(diào)用這個方法并使用其返回值進(jìn)行序列化。
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);
這種方法特別適合當(dāng)你需要為特定類定義統(tǒng)一的序列化規(guī)則時。
實際應(yīng)用場景
讓我們來看一個綜合應(yīng)用的例子。假設(shè)我們正在開發(fā)一個任務(wù)管理系統(tǒng):
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
函數(shù)會對每個屬性執(zhí)行,在處理大型對象時可能影響性能。只在必要時使用它們。
錯誤處理:JSON.parse()
在遇到無效JSON時會拋出異常,記得用try-catch包裝:
try {
const data = JSON.parse(invalidJsonString);
} catch (error) {
console.error('解析JSON失敗:', error);
}
安全性:永遠(yuǎn)不要直接解析來自不可信源的JSON數(shù)據(jù),這可能帶來安全風(fēng)險。始終驗證和清理輸入數(shù)據(jù)。
轉(zhuǎn)自?https://juejin.cn/post/7545758149861736500
該文章在 2025/9/8 8:55:48 編輯過