在前端项目中经常遇到将对象转为JSON字符串的需要,因为在数据请求过程中,参数数据可能需要转化为字符串以方便传输或存储。而且,返回的数据如果是JSON字符串格式,前端还需要将JSON字符串转化为对象,以方便使用。因此JSON.stringify和JSON.parse是经常用到的。我在这里记录一下两个方法的简单使用,以及一些简单的内部原理,希望自己能更好的理解和使用这两个方法。
使用方法:
JSON.stringify
该方法是将一个JavaScript值(通常是对象或者数组)转换为一个 JSON字符串。
- 用法:JSON.stringify(value[, replacer [, space]])
-
参数 描述 value 要转换的 JavaScript 值(通常为对象或数组)。 replacer 可选。用于执行转换的函数或数组。
(1)如果 replacer 为函数,则 JSON.stringify 将调用该函数,并传入每个成员的键和值。如果此函数返回 undefined,则排除成员。
(2)如果 replacer 是一个数组,则仅转换该数组中具有键值的成员。成员的转换顺序与键在数组中的顺序一样。当 value 参数也为数组时,将忽略 replacer 数组。如果该参数为null或者未提供,则对象所有的属性都会被序列化;
space 可选,指定缩进用的空白字符串,用于美化输出(pretty-print);如果参数是个数字,它代表有多少的空格;上限为10。该值若小于1,则意味着没有空格;如果该参数为字符串(字符串的前十个字母),该字符串将被作为空格;如果该参数没有提供(或者为null)将没有空格。space 也可以使用非数字,如:\t。
常用用法1:
JSON.stringify({}); // '{}'
JSON.stringify(true); // 'true'
JSON.stringify("foo"); // '"foo"'
JSON.stringify([1, "false", false]); // '[1,"false",false]'
JSON.stringify({ x: 5 }); // '{"x":5}'
JSON.stringify({x: 5, y: 6}); // "{"x":5,"y":6}"
JSON.stringify({x: undefined, y: Object, z: Symbol("")}); // '{}'
typeof Object // function
JSON.stringify([undefined, Object, Symbol("")]); // '[null,null,null]'
- 常用用法2 (重要),这两个方法在从对象中筛选出自己想要的那部分数据是非常有用的。
当 第二个参数为函数或数组时
//例1,参数为函数
function replacer(key, value) {
if (typeof value === "string") {
return undefined;
}
return value;
}
var foo = {foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7};
var jsonString = JSON.stringify(foo, replacer);
//JSON序列化结果为 '{"week":45,"month":7}'
//例2,参数为数组
//如果replacer是一个数组,数组的值代表将被序列化成JSON字符串的属性名。
JSON.stringify(foo, ['week', 'month']);
// '{"week":45,"month":7}', 只保留“week”和“month”属性值。
- 常用用法3
如果我们将对象用JSON.stringify字符串化,那么对象就会变得很不好分辨,因此我们可以用第三个参数space空格,来格式化对象,使字符串化的对象,也能很容易分辨出来里面的内容。
//space 参数用来控制结果字符串里面的间距。如果是一个数字, 则在字符串化时每一级别会比上一级
//别缩进多这个数字值的空格(最多10个空格);如果是一个字符串,则每一级别会比上一级别多缩进
//用该字符串(或该字符串的前十个字符)。
JSON.stringify({ a: 2 }, null, " "); // '{\n "a": 2\n}'
JSON.stringify({ uno: 1, dos : 2 }, null, '\t')
// '{ \
// "uno": 1, \
// "dos": 2 \
// }'
- 注意
(1)非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
(2)undefined、
任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null
(出现在数组中时)。函数、undefined被单独转换时,会返回undefined,如JSON.stringify(function(){})
or JSON.stringify(undefined)。
JSON.parse
该方法将JSON数据解析为最初的数据。
- 用法:JSON.parse(text[, reviver])
参数 | 描述 |
text | 必需, 一个有效的 JSON 字符串。 |
reviver | 可选,一个转换结果的函数, 将为对象的每个成员调用此函数。入参为当前属性名和属性值。 (1).如果reviver返回一个有效值,则对应的属性值将替换为转换后的值。 (2).如果reviver返回它接收的相同值,则不修改对应属性值。 (3).如果reviver返回undefined,则删除对应的属性。 |
var json = '{"result":true, "count":42}';
obj = JSON.parse(json);
console.log(obj.count);
// expected output: 42
解析值本身以及它所包含的所有属性,会按照一定的顺序(从最最里层的属性开始,一级级往外,最终到
达顶层,也就是解析值本身)分别的去调用 reviver 函数,在调用过程中,当前属性所属的对象会作为
this 值,当前属性名和属性值会分别作为第一个和第二个参数传入 reviver 中。
JSON.parse('{"p": 5}', function (k, v) {
if(k === '') return v; // 如果到了最顶层,则直接返回属性值,
return v * 2; // 否则将属性值变为原来的 2 倍。
}); // { p: 10 }
JSON.parse('{"1": 1, "2": 2,"3": {"4": 4, "5": {"6": 6}}}', function (k, v) {
console.log(k); // 输出当前的属性名,从而得知遍历顺序是从内向外的,
// 最后一个属性名会是个空字符串。
return v; // 返回原始属性值,相当于没有传递 reviver 参数。
});
// 1
// 2
// 4
// 6
// 5
// 3
// ""
- 注意:
// both will throw a SyntaxError
JSON.parse("[1, 2, 3, 4, ]");
JSON.parse('{"foo" : 1, }');
关于JSON.parse()和JSON.stringify()的一个非常重要的用法:深复制
JSON.parse(JSON.stringify(obj))可以深复制对象或数组。
var obj={
a:"ss",
b:"dd",
c:{
"d": "aa"
}
};
var obj1 = JSON.parse(JSON.stringify(obj));//拷贝数组,注意这行的拷贝方法
console.log(obj);
console.log(obj1);
obj1.c["d"]="change"; //改变obj1的c属性对象的d属性
console.log(obj); //不影响obj
//{
// a:"ss",
// b:"dd",
// c:{
// "d": "aa"
// }
//}
console.log(obj1);
//{
// a:"ss",
// b:"dd",
// c:{
// "d": "change"
// }
//}
为什么JSON.parse(JSON.stringify(obj))可以实现深复制?原因是:JSON.stringify先把对象转化为了字符串,程序会为这个字符串开辟一个新的存储空间存储。然后JSON.parse再把这个字符串解析为一个新的对象,就实现了深复制。
参考文章
https://www.cnblogs.com/chengxs/p/8656723.html
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
https://www.runoob.com/json/json-stringify.html
https://www.w3cschool.cn/javascript/javascript-t64x2ksc.html#