json.stringify和tostring区别,json.stringify json.parse
真的会用强大的JSON.stringify方法吗?下面这篇文章带你详细了解JSON.stringify,并介绍它的用法。希望对你有帮助!
JSON.stringify是日常开发中经常用到的。真的能灵活运用吗?
在研究这篇文章之前,鲍晓希望每个人都带着几个问题来学习stringify。【相关推荐:javascript视频教程】
Stringify函数有几个参数。每个参数有什么用?stringify的序列化标准是什么?函数序列化会做什么?null、undefined、NaN等特殊值怎么办?ES6和BigInt序列化后添加的符号类型会有什么特殊处理吗?为什么stringify不适合深度复制?你能想到stringify的这些妙用吗?文章的整个脉络和下面的思维导图是一致的,可以先做个印象。
三参数
在日常编程中,我们经常使用JSON.stringify方法将一个对象转换成JSON字符串形式。
const stu={
姓名: zcxiaobao ,
年龄:18岁
}
//{ 姓名: ZC小宝,年龄:18}
console . log(JSON . stringify(stu));但是stringify真的那么简单吗?我们先来看看MDN中stringify的定义。
MDN表示JSON.stringify()方法将JavaScript对象或值转换为JSON字符串。如果指定了replacer函数,则可以有选择地替换该值,或者如果指定的replacer是一个数组,则可以有选择地只包含该数组指定的属性。
读完定义后,鲍晓很惊讶。stringfy是否有多个参数?当然,stringify有三个参数。
让我们看看stringify语法和参数介绍:
Json.stringify (value [,replacer [,space]]) value:要排序到Json字符串中的值。Replacer(可选)如果该参数为函数,则序列化过程中,序列化值的每个属性都将被该函数转换和处理;
如果这个参数是数组,那么只有包含在这个数组中的属性名将被序列化为最终的JSON字符串。
如果此参数为空或未提供,对象的所有属性都将被序列化。
Space(可选):指定缩进的空白字符串,用于美化输出。如果参数是一个数字,它表示有多少个空格。上限是10。
如果该值小于1,则意味着没有空格。
如果参数是一个字符串(当字符串长度超过10个字母时,取前10个字母),该字符串将被用作空格。
如果未提供该参数(或为空),则没有空格。
replacer
让我们尝试使用replacer。
作为函数的替换器
作为一个函数,replacer有两个参数,key和值,这两个参数都将被序列化。
一开始,replacer 函数会被传入一个空字符串作为 key 值,代表着要被 stringify 的这个对象。重要的是要理解replacer函数在出现时并不把对象解析成键值对,而是先传入待序列化对象。然后每个对象或数组上的属性将依次传入。如果函数返回值为undefined或者函数时,该属性值会被过滤掉,其余按退货规则。
//replacer接受两个参数键值。
//键值是对象的每个键值对。
//所以我们可以简单地根据键或值的类型进行过滤
函数替换器(键,值){
if (typeof value===string) {
返回未定义的;
}
返回值;
}
//函数可以自己测试。
函数replacerFunc(key,value) {
if (typeof value===string) {
return()={ };
}
返回值;
}
const foo={foundation: Mozilla ,model: box ,周:45,transport: car ,月:7 };
const JSON string=JSON . stringify(foo,replacer);JSON序列化结果是{week:45, month:7}
但是,如果数组是序列化的,如果replacer函数返回undefined或function,则当前值不会被忽略,而是被null替换。
const list=[1, 22 ,3]
constjsonstring=JSON . stringify(list,replacer)JSON序列化的结果是[1,null,3]
以数组形式替换
由于数组很容易理解,所以过滤数组中出现的键值。
const foo={foundation: Mozilla ,model: box ,周:45,transport: car ,月:7 };
const JSON字符串=JSON。stringify(foo,[week , month ]);数据序列化结果为{ 周:45,月:7},只保留周和月属性值。
九特性
特性一: undefined、函数、Symbol值
出现在非数组对象属性值中:未定义,任意函数、符号值在序列化过程中将会被忽略
出现在数组中:未定义,任意函数、符号值会被转化为null
单独转换时:会返回undefined
//1.对象属性值中存在这三种值会被忽略
const obj={
姓名: zc ,
年龄:18,
//函数会被忽略
说你好(){
console.log(hello world )
},
//未定义会被忽略
妻子:未定义,
//符号值会被忽略
id:符号(111),
//[符号( zc)]: zc ,
}
//输出结果:{ 姓名: zc ,年龄:18}
控制台。log(JSON。stringify(obj));
//2.数组中这三种值会被转化为空
常量列表=[
zc ,
18,
//函数转化为空
函数说你好(){
console.log(hello world )
},
//未定义转换为空
未定义,
//符号转换为空
符号(111)
]
//[zc ,18,null,null,null]
控制台。log(JSON。stringify(列表))
//3.这三种值单独转化将会返回不明确的
控制台。log(JSON。stringify(未定义))//未定义
控制台。log(JSON。stringify(符号(111))//未定义
console.log(JSON.stringify(函数说你好(){
console.log(hello world )
})) //未定义
特性二: toJSON() 方法
转换值如果有托伊森方法,托吉森()方法返回什么值,序列化结果就返回什么值,其余值会被忽略。
const obj={
姓名: zc ,
toJSON(){
return return toJSON
}
}
//返回到杰森
控制台。log(JSON。stringify(obj));
特性三: 布尔值、数字、字符串的包装对象
布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值
JSON。stringify([新数字(1),新字符串( zcxiaobao ),新布尔(真)]);
//[1, zcxiaobao ,true]
特性四: NaN Infinity null
特性四主要针对Java脚本语言里面的特殊值,例如数字类型里的圆盘烤饼和无穷及零。此三种数值序列化过程中都会被当做 null。
//[空,空,空,空,空]
JSON.stringify([null,NaN,-NaN,Infinity,-Infinity])
//特性三讲过布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值
//隐式类型转换就会调用包装类,因此会先调用数字=南
//之后再转化为空
//1/0=无穷大=空
JSON。stringify([数字( 123a , 123a ,1/0])
特性五: Date对象
日期对象上部署了托吉森方法(同Date.toISOString())将其转换为字符串,因此JSON.stringify() 将会序列化 Date 的值为时间格式字符串。
//2022-03-06T08:24:56.138Z
JSON.stringify(新日期())
特性六: Symbol
特性一提到,符号类型当作值来使用时,对象、数组、单独使用分别会被忽略、转换为零,转化为未定义。
同样的,所有以 Symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。
const obj={
姓名: zcxiaobao ,
年龄:18,
[符号( lyl)]:唯一
}
函数替换器(键,值){
if (typeof key===symbol) {
返回值;
}
}
//未定义
JSON.stringify(obj,replacer);通过上面案例,我们可以看出,虽然我们通过替代者强行指定了返回标志类型值,但最终还是会被忽略掉。
特性七: BigInt
JSON.stringify规定:尝试去转换 BigInt 类型的值会抛出 TypeError
const bigNumber=BigInt(1)
//未捕获的类型错误:不知道如何序列化大整数
控制台。log(JSON。stringify(大数字))
特性八: 循环引用
特性八指出:对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误
日常开发中深拷贝最简单暴力的方式就是使用JSON.parse(JSON.stringify(obj)),但此方法下的深拷贝存在巨坑,关键问题就在于字符串化无法处理循环引用问题。
const obj={
姓名: zcxiaobao ,
年龄:18,
}
const loopObj={
目标文件
}
//形成循环引用
obj。loop obj=loop obj
JSON.stringify(obj)
/*未捕获的类型错误:将循环结构转换为数据
-从具有构造函数"对象"的对象开始
属性"循环对象"具有构造函数"对象"的对象
-属性" obj "封闭循环
在JSON.stringify(匿名)
在无名氏:10:6
*/
特性九: 可枚举属性
对于对象(包括地图/套件/WeakMap/WeakSet)的序列化,除了上文讲到的一些情况,纤细的也明确规定,仅会序列化可枚举的属性
//不可枚举的属性默认会被忽略
//{ 年龄:18}
JSON.stringify(
对象.创建(
空,
{
名称:{ value: zcxiaobao ,可枚举:false },
年龄:{值:18,可枚举:真}
}
)
);
六妙用
localStorage
localStorage对象用于长期存储整个网站的数据,存储的数据没有过期时间,直到被手动删除。我们通常将它存储为一个对象。
调用localStorage对象方法。
const obj={
姓名: zcxiaobao ,
年龄:18岁
}
//只需调用localStorage.setItem()
localStorage.setItem(zc ,obj);
//最终返回结果是[object Object]
//可以看出,单纯调用localStorage是失败的。
console . log(localstorage . getitem( ZC ))使用JSON.stringify方法的local storage
localStorage.setItem(zc ,JSON . stringify(obj));
//最后返回的结果是{name: zcxiaobao ,年龄:18}
console . log(JSON . parse(localStorage . getitem( ZC ))
属性过滤
假设这样一个场景,后端返回一个很长的对象,对象中有很多属性,但是我们只需要其中的几个,这些属性是要存储在local storage中的。
方案1:解构赋值字符串
//我们只需要一个,e,f属性
const obj={
a:1,b:2,c:3,d:4,e:5,f:6,g:7
}
//解构赋值
const {a,e,f }=obj
//存储到本地存储
localStorage.setItem(zc ,JSON.stringify({a,e,f}))
//{a:1, e:5, f:6}
console . log(local storage . getitem( ZC ))使用stringify的replacer参数。
//借助replacer作为数组过滤
localStorage.setItem(zc ,JSON.stringify(obj,[a , e , f]))
//{a:1, e:5, f:6}
console . log(local storage . getitem( ZC ))当replacer是一个数组时,它可以简单地过滤掉我们需要的属性,这是一个很好的技巧。
三思而后行之深拷贝
使用JSON.parse(JSON.stringify)是实现对象深度复制的最简单也是最暴力的方法之一。但如题,这种方法的深度复制要慎重考虑。
循环引用问题,stringify将报告错误
函数,未定义,符号被忽略。
NaN、Infinity和-Infinity被序列化为null。
.
所以在使用JSON.parse(JSON.stringify)做深度复制的时候,一定要慎重考虑。没有以上隐患,JSON.parse(JSON.stringify)是一个可行的深度复制方案。
对象的 map 函数
用数组编程时,我们经常使用map函数。有了replacer参数,我们就可以用这个参数来实现对象的贴图功能。
const ObjectMap=(obj,fn)={
if (typeof fn!==函数){
throw new TypeError(`${fn}不是函数!`);
}
//首先调用JSON.stringify(obj,replacer)实现map函数。
//然后调用JSON.parse将其再次转换为对象
返回JSON.parse(JSON.stringify(obj,fn));
};
//例如,将obj对象的属性值乘以下面的2
const obj={
答:1,
乙:2,
丙:3
}
console.log(ObjectMap(obj,(key,val)={
if (typeof value===number) {
返回值* 2;
}
返回值;
}))很多同学可能会很奇怪。为什么要在里面多加一个判词?就不能返回值* 2吗?
如上所述,replacer函数首先传入要序列化的对象对象 * 2 = NaN = toJSON(NaN) = undefined = 被忽略,因此没有后续的键值对解析。
删除对象属性
借助replacer函数,我们还可以删除对象的一些属性。
const obj={
姓名: zcxiaobao ,
年龄:18岁
}
//{ 年龄:18}
JSON.stringify(obj,(key,val)={
//当返回值未定义时,该属性将被忽略
if (key===name) {
返回未定义的;
}
返回val
})
对象判断
JSON.stringify可以将对象序列化为字符串,所以我们可以借助字符串实现简单的对象相等判断。
//确定数组是否包含对象
常量名称=[
{姓名: zcxiaobao},
{name:txtx},
{姓名:我的 },
];
const ZC xiaobao={ name: ZC xiaobao };
//真
JSON.stringify(名称)。包括(JSON.stringify(zcxiaobao))
//确定对象是否相等
const d1={type: div}
const d2={type: div}
//真
JSON . stringify(D1)===JSON . stringify(D2);
数组对象去重
借助以上思路,我们还可以实现数组对象的简单去重。
但是因为JSON.stringify序列化{x:1,y:1}和{y:1,x:1}的结果不同,所以我们需要在开始之前处理数组中的对象。
方法1:按字典顺序排列数组中每个对象的键。
arr.forEach(item={
const new item={ };
Object.keys(item) //获取对象键值。sort() //键值排序。map(key={//生成新对象
new item[key]=item[key];
})
//使用newItem执行重复数据删除操作
})但是第一种方法有些繁琐。JSON.stringify提供了replacer数组格式参数,可以过滤数组。
方法2:借助replacer数组格式
唯一函数(arr) {
const key Set=new Set();
const uniqueObj={}
//提取所有密钥
arr.forEach(item={
Object.keys(项目)。forEach(key=keySet.add(key))
})
const replacer=[.密钥集];
arr.forEach(item={
//根据指定的键值替换器过滤所有对象
unique[JSON.stringify(item,replacer)]=item;
})
返回Object.keys(唯一)。map(u=JSON.parse(u))
}
//测试一下
唯一([{},{},
{x:1},
{x:1},
{a:1},
{x:1,a:1},
{x:1,a:1},
{x:1,a:1,b:1}
])
//返回结果
[{},{x: 1},{a: 1},{x: 1},{x: 1, a: 1, b :1 }][相关推荐:web前端]以上就是带你穿越JSON。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。