- 原文地址:The 80/20 Guide to JSON.stringify in JavaScript
- 原文做者:Valeri Karpov
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:JerryFD
- 校對者:Usey95,mnikn
函數 JSON.stringify()
是一個把 JavaScript object 轉換成 JSON 的標準方法。不少 JavaScript 框架在底層都使用了 JSON.stringify()
,例如:Express' res.json()
、Axios' post()
和 Webpack stats 都在底層調用了 JSON.stringify()
。這篇文章會提供一個實用的、包含異常狀況的 JSON.stringify()
的概述。javascript
幾乎全部現代的 JavaScript 運行環境都支持 JSON.stringify()
。甚至 IE 瀏覽器自從 IE8 起就支持JSON.stringify()。下面是一個把普通的 object 轉換成 JSON 的例子:html
const obj = { answer: 42 };
const str = JSON.stringify(obj);
str; // '{"answer":42}'
typeof str; // 'string'
複製代碼
如你所見,下面的例子是 JSON.stringify()
和 JSON.parse()
一塊兒使用的。這種寫法能夠用來深拷貝 JavaScript 對象。前端
const obj = { answer: 42 };
const clone = JSON.parse(JSON.stringify(obj));
clone.answer; // 42
clone === obj; // false
複製代碼
若是 JSON.stringify()
的參數是 cyclical object,則會拋出一個錯誤。也就是說,若是對象 obj
有一個屬性,這個屬性的值是 obj
自己,那麼 JSON.stringify()
會拋出一個錯誤。java
const obj = {};
// 循環 object 指向它自身
obj.prop = obj;
// 拋出 "TypeError: TypeError: Converting circular structure to JSON"
JSON.stringify(obj);
複製代碼
這是 JSON.stringify()
惟一拋出異常的場景,除非你使用自定義的 toJSON()
函數或者使用替代函數(replacer)。然而即使這樣,你也仍是得把 JSON.stringify()
包在 try/catch
裏調用,由於循環 objects 仍是可能會出現。android
還有不少邊界場景 JSON.stringify()
不會拋出異常,但其結果可能不如你所想。好比,JSON.stringify()
會把 NaN
和 Infinity
轉換成 null
:webpack
const obj = { nan: parseInt('not a number'), inf: Number.POSITIVE_INFINITY };
JSON.stringify(obj); // '{"nan":null,"inf":null}'
複製代碼
JSON.stringify()
也會把屬性值爲函數或者 undefined
的內容幹掉:ios
const obj = { fn: function() {}, undef: undefined };
// 空 object `JSON.stringify()` 過濾 functions 和 `undefined`。
JSON.stringify(obj); // '{}'
複製代碼
JSON.stringify()
的第一個參數是要被序列化成 JSON 的 object。實際上 JSON.stringify()
接受 3 個參數,第三個參數 spaces
(譯註:空隙)。參數 spaces
用來將 JSON 格式化輸出成方便閱讀的格式。git
參數 spaces
能夠是 string 或 number。若是 spaces
不是 undefined,那麼JSON.stringify()
則會把 JSON 中的每個 key 單獨做爲一行輸出,而且加上 spaces
的前綴。github
const obj = { a: 1, b: 2, c: 3, d: { e: 4 } };
// '{"a":1,"b":2,"c":3,"d":{"e":4}}'
JSON.stringify(obj);
// {
// "a": 1,
// "b": 2,
// "c": 3,
// "d": {
// "e": 4
// }
// }
JSON.stringify(obj, null, ' ');
// 使用 2 個空格來格式化 JSON 輸出。和上面的例子等價。
JSON.stringify(obj, null, 2);
複製代碼
把參數 spaces
做爲字符串使用時,雖然在實際場景中大可能是使用空格,但其實不限制必須全是空格。例如:web
// {
// __"a": 1,
// __"b": 2,
// __"c": 3,
// __"d": {
// ____"e": 4
// __}
// }
JSON.stringify(obj, null, '__');
複製代碼
JSON.stringify()
的第二個參數是 replacer
函數。在上面的例子中,replacer
是 null
。JavaScript 針對 object 中的每個 key/value 對都會調用 replacer 函數,使用函數的返回值做爲屬性的值。例如:
const obj = { a: 1, b: 2, c: 3, d: { e: 4 } };
// `replacer` 使每一個數字的值加 1。輸出:
// '{"a":2,"b":3,"c":4,"d":{"e":5}}'
JSON.stringify(obj, function replacer(key, value) {
if (typeof value === 'number') {
return value + 1;
}
return value;
});
複製代碼
替代函數(譯註:replacer)在過濾敏感詞的場景很是有用。例如,假設你想過濾全部包含 'password' 及 'password' 子字符串的 keys:
const obj = {
name: 'Jean-Luc Picard',
password: 'stargazer',
nested: {
hashedPassword: 'c3RhcmdhemVy'
}
};
// '{"name":"Jean-Luc Picard","nested":{}}'
JSON.stringify(obj, function replacer(key, value) {
// 這個函數會被調用 5 次。 `key` 等於:
// '', 'name', 'password', 'nested', 'hashedPassword'
if (key.match(/password/i)) {
return undefined;
}
return value;
});
複製代碼
toJSON()
JSON.stringify()
函數會遍歷 object 尋找含有 toJSON()
函數的屬性。若是它找到了 toJSON()
函數,JSON.stringify()
會調用 toJSON()
函數,並使用其返回值做爲替代。例如:
const obj = {
name: 'Jean-Luc Picard',
nested: {
test: 'not in output',
toJSON: () => 'test'
}
};
// '{"name":"Jean-Luc Picard","nested":"test"}'
JSON.stringify(obj);
複製代碼
函數 toJSON()
能夠返回任何值,包括對象、原始類型的值,甚至 undefined
。若是 toJSON()
返回 undefined
,JSON.stringify()
會忽略這個屬性。
許多 JavaScript 模塊使用 toJSON()
這一特性來保證複雜的對象能被正確的序列化。好比 Mongoose documents 和 Moment objects。
函數 JSON.stringify()
是 JavaScript 基礎的核心。許多庫和框架在底層都使用了它,因此對 JSON.stringify()
的紮實理解,能夠幫助更好的學習你感興趣的 npm 模塊。好比,針對你的 Express REST API,能夠借用自定義 toJSON()
函數的能力來處理原生的 Date
類,以此實現一個日期格式化 的替代方案,或者,當使用 Axios 發送 HTTP 請求時,確保客戶端的循環對象能被正確的轉換成 JSON。(譯註:帕累托法則即 80/20 Rule,通常指 20% 的輸入,決定 80% 的結果的現象。)
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。