- 原文地址: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、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。