We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JSON.stringify是一个基本上所有前端工程师都不陌生的方法。
👉🏻 JSON(JavaScript Object Notation)是由ECMA标准化(ECMA-404)的一种轻量级的数据交换格式。它来源于ECMAScript,是一种便于人阅读和理解的数据交换格式,目前被几乎所有的主流语言和平台支持。
JSON.stringify和JSON.parse是一对处理数据的常用方法,前者将JavaScript的对象转为JSON字符串,后者将一个JSON串解析为JavaScript的对象。
const obj = {foo: 'bar'}; const str = JSON.stringify(obj); // {"foo":"bar"} console.log(str); const obj2 = JSON.parse(str); console.log(obj2); // [Object object]{foo: "bar"}
JSON作为数据格式,既能被平台处理,又能方便人阅读,JavaScript的JSON.stringify在处理数据的时候同时考虑了数据转换和方便阅读,只不过,方便阅读这一点,常常被人忽略。
我们看一下
<textarea id="show-score"></textarea>
const students = [ { name: 'akira', score: 100, }, { name: 'John', score: 60, }, { name: 'Jane', score: 90, } ]; const textarea = document.getElementById('show-score'); textarea.textContent = JSON.stringify(students);
上面的代码,我们将学生成绩单显示在页面上一个textarea里,如果我们直接将students通过JSON.stringify转成字符串显示,它是不包含空白符的,不方便人阅读。
在JSON.stringify方法一共能接受3个参数,其中两个可选的参数,最后一个参数是用来格式化显示的,我们看一下:
const students = [ { name: 'akira', score: 100, }, { name: 'John', score: 60, }, { name: 'Jane', score: 90, } ]; const textarea = document.getElementById('show-score'); textarea.textContent = JSON.stringify(students, null, 4);
我们暂时不管stringify的第二个参数,看一下它的第三个参数,在这里我们将它设为4,表示用每行缩进4个空格的格式来格式化stringify后的字符串:
我们也可以用字符串而不是数字来传这个参数,如果用字符串,则表示用该字符串作为占位符缩进:
textarea.textContent = JSON.stringify(students, null, '\t');
除了设置缩进格式和占位符,我们还有更灵活的控制方式,我们看一下:
const students = [ { name: 'akira', score: 100, }, { name: 'John', score: 60, }, { name: 'Jane', score: 90, } ]; const textarea = document.getElementById('show-score'); textarea.textContent = JSON.stringify(students, ["name"], 4);
上面的代码,我们传一个["name"]数组给stringify方法,表示只序列化对象中的"name"属性,这样我们就会得到一个只包含学生名不包含成绩的数据:
["name"]
"name"
💡当我们传数组给stringify的第二个参数时,其中的内容表示可序列化的属性名,而且这个设定是递归的,比如:
const data = { name: { name: 'aa', foo: 'bar', }, foo: 'bar', other: { name: 'bb', }, } const result = JSON.stringify(data, ["name"]); console.log(result); // {name: {name: 'aa'}}
比如上面的代码,最后只会序列化{name: {name: 'aa'}} 其他的属性都会被过滤掉。
{name: {name: 'aa'}}
除了传数组,我们还可以传一个函数作为这个参数:
const students = [ { name: 'akira', score: 100, }, { name: 'John', score: 60, }, { name: 'Jane', score: 90, } ]; function replacer(key, value) { if(key === 'score') { if (value === 100) { return 'S'; } else if(value >= 90) { return 'A'; } else if(value >= 70) { return 'B'; } else if(value >= 50) { return 'C'; } else { return 'E'; } } return value; } const textarea = document.getElementById('show-score'); textarea.textContent = JSON.stringify(students, replacer, 4);
上面的代码,我们通过replacer将成绩从百分制替换为SABCE的成绩。
👉🏻 如果stringify的第二个参数为函数那么它的返回值如果是undefined,那么对应的属性不会被序列化,如果返回其他的值,那么用返回的值替代原来的值进行序列化。
如果这个函数返回一个对象,那么这个对象也会用同样的replacer递归地序列化。
const students = [ { name: 'akira', score: 100, }, { name: 'John', score: 60, }, { name: 'Jane', score: 90, } ]; function replacer(key, value) { if(key === 'score') { if (value === 100) { return {score: value, level: 'S'}; } else if(value >= 90) { return {score: value, level: 'A'}; } else if(value >= 70) { return {score: value, level: 'B'}; } else if(value >= 50) { return {score: value, level: 'C'}; } else { return {score: value, level: 'E'}; } } return value; } const textarea = document.getElementById('show-score'); textarea.textContent = JSON.stringify(students, replacer, 4);
上面的代码会导致堆栈溢出,因为return {score: value, level: 'S'}返回的对象中依然还有score属性,然后被函数递归地序列化,造成死循环。要避免这种情况,我们只需要修改一下,比如改变一下属性名:
return {score: value, level: 'S'}
const students = [ { name: 'akira', score: 100, }, { name: 'John', score: 60, }, { name: 'Jane', score: 90, } ]; function replacer(key, value) { if(key === 'score') { if (value === 100) { return {point: value, level: 'S'}; } else if(value >= 90) { return {point: value, level: 'A'}; } else if(value >= 70) { return {point: value, level: 'B'}; } else if(value >= 50) { return {point: value, level: 'C'}; } else { return {point: value, level: 'E'}; } } return value; } const textarea = document.getElementById('show-score'); textarea.textContent = JSON.stringify(students, replacer, 4);
上面代码将返回的对象的score属性名替换成point就可以了。
与 JSON.stringify 对应,JSON.parse 也有一个额外的参数,可以传一个函数:
const str = '{"result":true, "count":42}'; const result = JSON.parse(str, (key, value) => { if(typeof value === 'number') return value * 2; return value; }); console.log(result); // {result: true, count: 84}
所以,JavaScript可以更灵活地处理JSON。这些高级的参数,你平时使用过吗?关于JSON,还有什么其他内容想要讨论,欢迎在issue中讨论。
The text was updated successfully, but these errors were encountered:
JSON.stringify 面对属性里面包含自身的对象有什么优雅的处理方法吗
Sorry, something went wrong.
@q269384828 没啥好办法,JSON.stringify设计时就是不考虑circular的。你需要structured clone(目前不在js标准里)。
No branches or pull requests
JSON.stringify是一个基本上所有前端工程师都不陌生的方法。
👉🏻 JSON(JavaScript Object Notation)是由ECMA标准化(ECMA-404)的一种轻量级的数据交换格式。它来源于ECMAScript,是一种便于人阅读和理解的数据交换格式,目前被几乎所有的主流语言和平台支持。
JSON.stringify和JSON.parse是一对处理数据的常用方法,前者将JavaScript的对象转为JSON字符串,后者将一个JSON串解析为JavaScript的对象。
JSON作为数据格式,既能被平台处理,又能方便人阅读,JavaScript的JSON.stringify在处理数据的时候同时考虑了数据转换和方便阅读,只不过,方便阅读这一点,常常被人忽略。
我们看一下
上面的代码,我们将学生成绩单显示在页面上一个textarea里,如果我们直接将students通过JSON.stringify转成字符串显示,它是不包含空白符的,不方便人阅读。
在JSON.stringify方法一共能接受3个参数,其中两个可选的参数,最后一个参数是用来格式化显示的,我们看一下:
我们暂时不管stringify的第二个参数,看一下它的第三个参数,在这里我们将它设为4,表示用每行缩进4个空格的格式来格式化stringify后的字符串:
我们也可以用字符串而不是数字来传这个参数,如果用字符串,则表示用该字符串作为占位符缩进:
除了设置缩进格式和占位符,我们还有更灵活的控制方式,我们看一下:
上面的代码,我们传一个
["name"]
数组给stringify方法,表示只序列化对象中的"name"
属性,这样我们就会得到一个只包含学生名不包含成绩的数据:💡当我们传数组给stringify的第二个参数时,其中的内容表示可序列化的属性名,而且这个设定是递归的,比如:
比如上面的代码,最后只会序列化
{name: {name: 'aa'}}
其他的属性都会被过滤掉。除了传数组,我们还可以传一个函数作为这个参数:
上面的代码,我们通过replacer将成绩从百分制替换为SABCE的成绩。
👉🏻 如果stringify的第二个参数为函数那么它的返回值如果是undefined,那么对应的属性不会被序列化,如果返回其他的值,那么用返回的值替代原来的值进行序列化。
如果这个函数返回一个对象,那么这个对象也会用同样的replacer递归地序列化。
上面的代码会导致堆栈溢出,因为
return {score: value, level: 'S'}
返回的对象中依然还有score属性,然后被函数递归地序列化,造成死循环。要避免这种情况,我们只需要修改一下,比如改变一下属性名:上面代码将返回的对象的score属性名替换成point就可以了。
扩展
与 JSON.stringify 对应,JSON.parse 也有一个额外的参数,可以传一个函数:
所以,JavaScript可以更灵活地处理JSON。这些高级的参数,你平时使用过吗?关于JSON,还有什么其他内容想要讨论,欢迎在issue中讨论。
The text was updated successfully, but these errors were encountered: