在JavaScript中,JSON.stringify()方法用于将 JavaScript 对象或值转换为 JSON 字符串。如果对象有toJSON方法,JSON.stringify 就会调用对象的toJSON方法,以toJSON方法返回的值为序列化值 。
举个例子,以下代码结果与 JSON.stringify({ answer: 42 })
相同。
1
2
3
4
5
|
const json = JSON.stringify({
answer: { toJSON: () => 42 }
});
console.log(json); // {"answer":42}
|
与 ES6 类结合
toJSON非常有利于ES6类对象正常序列化。举个例子,你通过Error类型扩展一个HTTPError类。
1
2
3
4
5
6
|
class HTTPError extends Error {
constructor(message, status) {
super(message);
this.status = status;
}
}
|
JavaScript不会很好的序列化错误信息。默认情况下,以下脚本只会输出:{"status":404}
,没有错误信息及错误堆栈跟踪。
1
2
3
4
5
6
7
8
9
|
class HTTPError extends Error {
constructor(message, status) {
super(message);
this.status = status;
}
}
const e = new HTTPError('Fail', 404);
console.log(JSON.stringify(e)); // {"status":404}
|
但如果在HTTPError类型中添加toJSON方法,效果会好很多。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class HTTPError extends Error {
constructor(message, status) {
super(message);
this.status = status;
}
toJSON() {
return { message: this.message, status: this.status };
}
}
const e = new HTTPError('Fail', 404);
console.log(JSON.stringify(e)); // {"message":"Fail","status":404}
|
你还可以通过toJSON方法添加更多调试信息,假如你的NODE_ENV处于开发环境,你可以为错误添加堆栈信息,方便调试。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class HTTPError extends Error {
constructor(message, status) {
super(message);
this.status = status;
}
toJSON() {
const ret = { message: this.message, status: this.status };
if (process.env.NODE_ENV === 'development') {
ret.stack = this.stack;
}
return ret;
}
}
const e = new HTTPError('Fail', 404);
// {"message":"Fail","status":404,"stack":"Error: Fail\n at ...
console.log(JSON.stringify(e));
|
toJSON最好的地方是可以帮你处理嵌套信息。通过toJSON你仍然可以正确地序列化数组中深层嵌套的HTTPError实例和HTTPError实例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class HTTPError extends Error {
constructor(message, status) {
super(message);
this.status = status;
}
toJSON() {
return { message: this.message, status: this.status };
}
}
const e = new HTTPError('Fail', 404);
// {"nested":{"message":"Fail","status":404},"arr":[{"message":"Fail","status":404}]}
console.log(JSON.stringify({
nested: e,
arr: [e]
}));
|
很多类库都是通过toJSON来JSON.stringify自定义化。如 Express 的res.json()方法、Axios POST requests序列化对象等。
toJSON()
实际应用
Moment.js类库为对象自定义了toJSON方法:
1
2
3
4
|
function toJSON () {
// JSON.stringify(new Date(NaN)) === 'null'
return this.isValid() ? this.toISOString() : 'null';
}
|
你可以直接调用toJSON序列化日期对象:
1
2
|
const moment = require('moment');
console.log(moment('2019-06-01').toJSON.toString());
|
Node.js buffers 对象也自定toJSON方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
const buf = Buffer.from('abc');
console.log(buf.toJSON.toString());
// Prints:
function toJSON() {
if (this.length > 0) {
const data = new Array(this.length);
for (var i = 0; i < this.length; ++i)
data[i] = this[i];
return { type: 'Buffer', data };
} else {
return { type: 'Buffer', data: [] };
}
}
|
Mongoose文档对象也具有toJSON()函数,以确保Mongoose文档对象的内部状态不会出现在JSON.stringify()输出中。
小结
toJSON()函数是JavaScript构建类时重要的工具。通过这种方式,您可以控制JavaScript如何将你的类实例序列化为json字符串。 toJSON()函数可以帮助您解决许多问题,例如确保日期对象得到正确的格式或Node.js缓冲对象正常序列化。下次构造ES6类型时,一定要记得尝试哦。