Skip to content

Commit

Permalink
JavaScript 中 JSON.stringify 的二八法则 (#6006)
Browse files Browse the repository at this point in the history
* 翻译完成

翻译完成

* 校对修改

校对修改

* 添加校对者

添加校对者

* 译文格式问题修正

* 修改标题

修改标题
  • Loading branch information
Jerry-FD authored and leviding committed Jun 25, 2019
1 parent 60a918d commit 0c50f62
Showing 1 changed file with 30 additions and 32 deletions.
62 changes: 30 additions & 32 deletions TODO1/the-80-20-guide-to-json-stringify-in-javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
> * 原文作者:[Valeri Karpov](http://www.twitter.com/code_barbarian)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 本文永久链接:[https://github.com/xitu/gold-miner/blob/master/TODO1/the-80-20-guide-to-json-stringify-in-javascript.md](https://github.com/xitu/gold-miner/blob/master/TODO1/the-80-20-guide-to-json-stringify-in-javascript.md)
> * 译者:
> * 校对者:
> * 译者:[JerryFD](https://github.com/Jerry-FD)
> * 校对者:[Usey95](https://github.com/Usey95)[mnikn](https://github.com/mnikn)
# The 80/20 Guide to JSON.stringify in JavaScript
# JavaScript 中 JSON.stringify 的二八法则

The [`JSON.stringify()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) is the canonical way to convert a JavaScript object to [JSON](https://www.json.org/). Many JavaScript frameworks use `JSON.stringify()` under the hood: [Express' `res.json()`](http://expressjs.com/en/4x/api.html#res.json), [Axios' `post()`](https://github.com/axios/axios#example), and [Webpack stats](https://webpack.js.org/configuration/stats/) all call `JSON.stringify()`. In this article, I'll provide a practical overview of `JSON.stringify()`, including error cases.
[函数 `JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) 是一个把 JavaScript object 转换成 [JSON](https://www.json.org/) 的标准方法。很多 JavaScript 框架在底层都使用了 `JSON.stringify()`,例如:[Express' `res.json()`](http://expressjs.com/en/4x/api.html#res.json)[Axios' `post()`](https://github.com/axios/axios#example) [Webpack stats](https://webpack.js.org/configuration/stats/) 都在底层调用了 `JSON.stringify()`。这篇文章会提供一个实用的、包含异常情况的 `JSON.stringify()` 的概述。

## Getting Started
## 开始

All modern JavaScript runtimes support `JSON.stringify()`. Even Internet Explorer has [`JSON.stringify()` support since IE8](https://blogs.msdn.microsoft.com/ie/2008/09/10/native-json-in-ie8/). Here's an example of converting a simple object to JSON:
几乎所有现代的 JavaScript 运行环境都支持 `JSON.stringify()`。甚至 IE 浏览器自从 [IE8 起就支持JSON.stringify()](https://blogs.msdn.microsoft.com/ie/2008/09/10/native-json-in-ie8/)。下面是一个把普通的 object 转换成 JSON 的例子:

```javascript
const obj = { answer: 42 };
Expand All @@ -21,7 +21,7 @@ str; // '{"answer":42}'
typeof str; // 'string'
```

You may see `JSON.stringify()` used with [`JSON.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse) as shown below. This pattern is one way of [deep cloning a JavaScript object](https://flaviocopes.com/how-to-clone-javascript-object/#json-serialization).
如你所见,下面的例子是 `JSON.stringify()` [`JSON.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse) 一起使用的。这种写法可以用来[深拷贝 JavaScript 对象](https://flaviocopes.com/how-to-clone-javascript-object/#json-serialization)

```javascript
const obj = { answer: 42 };
Expand All @@ -31,44 +31,43 @@ clone.answer; // 42
clone === obj; // false
```

## Errors and Edge Cases
## 错误和边界处理

[`JSON.stringify()` throws an error when it detects a cyclical object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Exceptions). In other words, if an object `obj` has a property whose value is `obj`, `JSON.stringify()` will throw an error.
[如果 `JSON.stringify()` 的参数是 cyclical object,则会抛出一个错误](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Exceptions)。也就是说,如果对象 `obj` 有一个属性,这个属性的值是 `obj` 本身,那么 `JSON.stringify()` 会抛出一个错误。

```javascript
const obj = {};
// Cyclical object that references itself
// 循环 object 指向它自身
obj.prop = obj;

// Throws "TypeError: TypeError: Converting circular structure to JSON"
// 抛出 "TypeError: TypeError: Converting circular structure to JSON"
JSON.stringify(obj);
```

That is the only case where `JSON.stringify()` throws an exception, unless you're using custom `toJSON()` functions or replacer functions. However, you should still wrap `JSON.stringify()` calls in `try/catch`, because circular objects do pop up in practice.
这是 `JSON.stringify()` 唯一抛出异常的场景,除非你使用自定义的 `toJSON()` 函数或者使用替代函数(replacer)。然而即便这样,你也还是得把 `JSON.stringify()` 包在 `try/catch` 里调用,因为循环 objects 还是可能会出现。

There are several edge cases where `JSON.stringify()` doesn't throw an error, but you might expect it does. For example, `JSON.stringify()` converts `NaN` and `Infinity` to `null`:
还有很多边界场景 `JSON.stringify()` 不会抛出异常,但其结果可能不如你所想。比如,`JSON.stringify()` 会把 `NaN` `Infinity` 转换成 `null`

```javascript
const obj = { nan: parseInt('not a number'), inf: Number.POSITIVE_INFINITY };

JSON.stringify(obj); // '{"nan":null,"inf":null}'
```

`JSON.stringify()` also strips out properties whose values are functions or `undefined`:
`JSON.stringify()` 也会把属性值为函数或者 `undefined` 的内容干掉:

```javascript
const obj = { fn: function() {}, undef: undefined };

// Empty object. `JSON.stringify()` removes functions and `undefined`.
// object `JSON.stringify()` 过滤 functions `undefined`
JSON.stringify(obj); // '{}'
```

## Pretty Printing
## 优化输出

`JSON.stringify()` 的第一个参数是要被序列化成 JSON 的 object。实际上 `JSON.stringify()` 接受 3 个参数,第三个参数 `spaces`(译注:空隙)。参数 `spaces` 用来将 JSON 格式化输出成方便阅读的格式。

The first parameter to `JSON.stringify()` is the object to serialize to JSON. `JSON.stringify()` actually takes 3 parameters, and the 3rd parameter is called `spaces`. The `spaces` parameter is used for formatting JSON output in a human readable way.

You can set the `spaces` parameter to either be a string or a number. If `spaces` is not undefined, `JSON.stringify()` will put each key in the JSON output on its own line, and prefix each key with `spaces`.
参数 `spaces` 可以是 string 或 number。如果 `spaces` 不是 undefined,那么`JSON.stringify()` 则会把 JSON 中的每一个 key 单独作为一行输出,并且加上 `spaces` 的前缀。

```javascript
const obj = { a: 1, b: 2, c: 3, d: { e: 4 } };
Expand All @@ -86,11 +85,11 @@ JSON.stringify(obj);
// }
JSON.stringify(obj, null, ' ');

// Use 2 spaces when formatting JSON output. Equivalent to the above.
// 使用 2 个空格来格式化 JSON 输出。和上面的例子等价。
JSON.stringify(obj, null, 2);
```

The `spaces` string doesn't have to be all whitespace, although in practice it usually will be. For example:
把参数 `spaces` 作为字符串使用时,虽然在实际场景中大多是使用空格,但其实不限制必须全是空格。例如:

```javascript
// {
Expand All @@ -106,13 +105,12 @@ JSON.stringify(obj, null, '__');

## Replacers


The 2nd parameter to `JSON.stringify()` is the `replacer` function. In the above examples, `replacer` was `null`. JavaScript calls the replacer function with every key/value pair in the object, and uses the value the replacer function returns. For example:
`JSON.stringify()` 的第二个参数是 `replacer` 函数。在上面的例子中,`replacer``null`。JavaScript 针对 object 中的每一个 key/value 对都会调用 replacer 函数,使用函数的返回值作为属性的值。例如:

```javascript
const obj = { a: 1, b: 2, c: 3, d: { e: 4 } };

// `replacer` increments every number value by 1. The output will be:
// `replacer` 使每个数字的值加 1。输出:
// '{"a":2,"b":3,"c":4,"d":{"e":5}}'
JSON.stringify(obj, function replacer(key, value) {
if (typeof value === 'number') {
Expand All @@ -122,7 +120,7 @@ JSON.stringify(obj, function replacer(key, value) {
});
```

The replacer function is useful for omitting sensitive data. For example, suppose you wanted to omit all [keys that contain the substring 'password'](https://masteringjs.io/tutorials/fundamentals/contains-substring#case-insensitive-search):
替代函数(译注:replacer)在过滤敏感词的场景非常有用。例如,假设你想过滤所有[包含 'password' 及 'password' 子字符串的 keys](https://masteringjs.io/tutorials/fundamentals/contains-substring#case-insensitive-search)

```javascript
const obj = {
Expand All @@ -135,7 +133,7 @@ const obj = {

// '{"name":"Jean-Luc Picard","nested":{}}'
JSON.stringify(obj, function replacer(key, value) {
// This function gets called 5 times. `key` will be equal to:
// 这个函数会被调用 5 次。 `key` 等于:
// '', 'name', 'password', 'nested', 'hashedPassword'
if (key.match(/password/i)) {
return undefined;
Expand All @@ -144,9 +142,9 @@ JSON.stringify(obj, function replacer(key, value) {
});
```

## The `toJSON()` Function
## 函数 `toJSON()`

The `JSON.stringify()` function also traverses the object looking for properties that have a `toJSON()` function. If it finds a `toJSON()` function, `JSON.stringify()` calls the `toJSON()` function and uses the return value as a replacement. For example:
`JSON.stringify()` 函数会遍历 object 寻找含有 `toJSON()` 函数的属性。如果它找到了 `toJSON()` 函数,`JSON.stringify()` 会调用 `toJSON()` 函数,并使用其返回值作为替代。例如:

```javascript
const obj = {
Expand All @@ -161,13 +159,13 @@ const obj = {
JSON.stringify(obj);
```

The `toJSON()` function can return any value, including objects, primitives, or `undefined`. If `toJSON()` returns `undefined`, `JSON.stringify()` will ignore that property.
函数 `toJSON()` 可以返回任何值,包括对象、原始类型的值,甚至 `undefined`。如果 `toJSON()` 返回 `undefined``JSON.stringify()` 会忽略这个属性。

Many JavaScript modules use `toJSON()` to ensure sophisticated objects get serialized correctly, like [Mongoose documents](https://mongoosejs.com/docs/api.html#document_Document-toJSON) and [Moment objects](https://momentjs.com/docs/#/displaying/as-json/).
许多 JavaScript 模块使用 `toJSON()` 这一特性来保证复杂的对象能被正确的序列化。比如 [Mongoose documents](https://mongoosejs.com/docs/api.html#document_Document-toJSON) [Moment objects](https://momentjs.com/docs/#/displaying/as-json/)

## Moving On
## 后续

The `JSON.stringify()` function is a core JavaScript fundamental. Many libraries and frameworks use it under the hood, so a solid understanding of `JSON.stringify()` lets you do more with your favorite npm modules. For example, you can define alternate [date formatting](https://masteringjs.io/tutorials/fundamentals/date_format) for your Express REST API using a custom `toJSON()` function on the native `Date` class, or ensure that a circular client-side object gets converted to JSON correctly when sending an HTTP request with Axios.
函数 `JSON.stringify()` JavaScript 基础的核心。许多库和框架在底层都使用了它,所以对 `JSON.stringify()` 的扎实理解,可以帮助更好的学习你感兴趣的 npm 模块。比如,针对你的 Express REST API,可以借用自定义 `toJSON()` 函数的能力来处理原生的 `Date` 类,以此实现一个[日期格式化](https://masteringjs.io/tutorials/fundamentals/date_format) 的替代方案,或者,当使用 Axios 发送 HTTP 请求时,确保客户端的循环对象能被正确的转换成 JSON。(译注:帕累托法则即 80/20 Rule,一般指 20% 的输入,决定 80% 的结果的现象。)

> 如果发现译文存在错误或其他需要改进的地方,欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。
Expand Down

0 comments on commit 0c50f62

Please sign in to comment.