JSON.stringify()的陷阱及其隱藏的秘密
如果你接觸過 JavaScript,很有可能遇到過 JSON.stringify()—— 這個可靠的工具可以將對象轉(zhuǎn)換為 JSON 字符串。無論是通過 API 發(fā)送數(shù)據(jù)還是保存結(jié)構(gòu)化數(shù)據(jù),對于任何 Web 開發(fā)者來說,JSON.stringify() 實際上都是一個必經(jīng)之路。但盡管它看起來就像揮動魔杖一樣簡單,表面之下卻隱藏著陷阱。讓我們以一種有趣的方式深入探索 JSON.stringify() 這個古怪的世界,并了解一些歷史趣聞!
簡史:JSON.stringify() 從何而來?
在我們探索陷阱之前,讓我們回到它的最初。JSON.stringify()是在 ECMAScript 5(ES5)中引入的,該腳本于 2009 年完成。目的是什么?以機器和人類都可讀的方式簡化數(shù)據(jù)交換。
有趣的事實:JSON(JavaScript 對象表示法)本身最初是由 Douglas Crockford 在 2000 年代初期構(gòu)思的,他正在尋找一種輕量級的數(shù)據(jù)格式來取代 XML。
JSON.stringify() 的陷阱
1、循環(huán)引用:兜兜轉(zhuǎn)轉(zhuǎn)我們走!
循環(huán)引用是JSON.stringify()的最終禁忌。如果你嘗試字符串化引用自身的對象,你會得到一個很清晰的報錯:Uncaught TypeError。
const obj = {};
obj.self = obj;
JSON.stringify(obj); // Uncaught TypeError: Converting circular structure to JSON
有趣的事實:您可以說JSON.stringify()具有“無無限循環(huán)”策略!它只是不適合遞歸對象。要是逃離生活的圈子就這么容易就好了,對吧?
2、不可枚舉的屬性和符號?不受歡迎!
當使用JSON.stringify()時,任何不可枚舉或基于 Symbol 的屬性都會像魔術一樣消失得無影無蹤。
const obj = {};
Object.defineProperty(obj, 'hidden', { value: 'secret', enumerable: false });
obj[Symbol('id')] = 123;
console.log(JSON.stringify(obj)); // {}
有趣的事實:不可枚舉的屬性就像 JavaScript 的忍者 — 安靜、不可見,并且完全被JSON.stringify()忽略!
3、未定義的值是重影
undefined 值以及函數(shù)和 Symbol 將被完全忽略。它們不會在您的最終 JSON 輸出中被剪切。
const obj = {
name: 'John',
age: undefined,
greet: function() { console.log('Hello!'); },
};
console.log(JSON.stringify(obj)); // {"name":"John"}
有趣的事實:想象一下,undefined的價值觀就像在聚會上被排除在客人名單之外的人。如果他們不受歡迎,他們就不會出現(xiàn)!
4、NaN 和 Infinity — Math Gone MIA
如果您的對象包含 NaN 或 Infinity,則它們在最終的 JSON 字符串中將替換為 null。
const obj = { value: NaN, count: Infinity };
console.log(JSON.stringify(obj)); // {"value":null,"count":null}
有趣的事實:NaN是一個悖論。它被稱為 “數(shù)字”,但不是 1!難怪 JSON.stringify()把它當作幽靈。
5、日期變成字符串 — 不包括時間旅行
字符串化后,日期不會保留為 Date 對象。相反,它們將被轉(zhuǎn)換為 ISO 字符串。
const obj = { date: new Date() };
console.log(JSON.stringify(obj)); // {"date":"2024-09-11T12:00:00.000Z"}
有趣的事實:JavaScript 的 Date 對象因其怪癖而臭名昭著。至少當JSON.stringify()將其轉(zhuǎn)換為字符串時,它是一致的!
6、屬性順序 — 不是你所期望的
意外的JSON.stringify()不保留屬性的順序。事實上,它可能會按字母順序?qū)λ鼈冞M行排序。
const obj = { b: 1, a: 2 };
console.log(JSON.stringify(obj)); // {"a":2,"b":1}
有趣的事實:您可能會說JSON.stringify()有點強迫癥。它喜歡按字母順序排序,無論您喜歡與否!
原型消失 — 只剩下最基本的骨架
方法和原型屬性?逝。當JSON.stringify()執(zhí)行其操作時,它只留下對象的直接屬性。
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, ${this.name}!`);
};
const john = new Person('John');
console.log(JSON.stringify(john)); // {"name":"John"}
有趣的事實:原型就像電影中的幕后工作人員 — 必不可少,但觀眾從未見過(或者在這種情況下,JSON.stringify())。
JSON.stringify()參數(shù)的強大功能
雖然陷阱很多,但不要忘記JSON.stringify()通過其參數(shù)提供的強大自定義選項!
1、替代品:Filter Master
replacer參數(shù)允許您自定義字符串化的內(nèi)容。它可以是篩選或轉(zhuǎn)換值的函數(shù),也可以是將某些屬性列入白名單的數(shù)組。
replacer作為函數(shù):
const user = { name: 'John', age: 30 };
const jsonString = JSON.stringify(user, (key, value) => {
return key === 'age' ? undefined : value;
});
console.log(jsonString); // {"name":"John"}
replacer數(shù)組中:
const user = { name: 'John', age: 30, city: 'New York' };
const jsonString = JSON.stringify(user, ['name', 'city']);
console.log(jsonString); // {"name":"John","city":"New York"}
有趣的事實:replacer的爭論就像俱樂部的保鏢,決定誰可以進入,誰在門口被拒之門外。
2、space:JSON,但很漂亮
space參數(shù)允許您添加縮進以提高可讀性。無論您喜歡2個空格還是制表符,這個參數(shù)都是您的好朋友。
const obj = { name: 'John', age: 30 };
console.log(JSON.stringify(obj, null, 2));
/*
{
"name": "John",
"age": 30
}
*/
console.log(JSON.stringify(obj, null, "*****"));
/*
{
*****"name": "John",
*****"age": 30
}
*/
有趣的事實:space爭論就像你的室內(nèi)設計師。它使您的 JSON 輸出看起來美觀,因為誰不喜歡一些好的格式呢?
結(jié)論
要接受JSON.stringify()的怪異之處。
JSON.stringify()乍一看可能很簡單,但它充滿了怪癖、邊緣情況和隱藏的力量。通過了解它的局限性并利用它的論點,您可以避免常見的陷阱并像專業(yè)人士一樣使用它。
請記住,這不僅僅是將對象轉(zhuǎn)換為字符串,而是了解數(shù)據(jù)的表示方式。因此,下次您使用JSON.stringify()時,您將準備好避開它隱藏的陷阱并充分利用它的靈活性!