前言项目有bug。为了保留JSON对象,组件使用JSON.stringify将其转换为字符串。这当然是为了避免对象成为引用类型。数据源的污染。但是后面使用JSON.parse方法后,发现数据变了。代码简化:letobj={name:'Gopal',age:Infinity}letoriginObj=JSON.stringify(obj)console.log(originObj)//{"name":"Gopal","age":null}是ok看,Infinity变为null,这导致了以下错误。其实在我踩JSON.stringify的项目中已经有很多坑了。借此机会整理一下,给大家参考一下。先说说这个问题的解决方法:解决方法一:简单粗暴,重新赋值age属性解决方法二:functioncensor(key,value){if(value===Infinity){return"Infinity";}返回值;}varb=JSON.stringify(a,censor);varc=JSON.parse(b,function(key,value){returnvalue==="Infinity"?Infinity:value;});这个有点乱是的,作为参考,其实我是直接用的第一种方法。但是这里可以看到JSON.stringify其实还有第二个参数,那么它有什么用呢?接下来我们揭开它的神秘面纱。JSON.stringify基本语法JSON.stringify(value[,replacer[,space]])概念MDN中文文档解释如下:JSON.stringify()方法将一个JavaScript值(对象或数组)转换为JSON字符串,如果指定的替换器是函数,则可选择替换值,或者如果指定的替换器是数组,则可选择仅包含数组指定的属性。我个人认为这种解释是不恰当的。不合适的地方在于“objectorarray”,因为其实对于普通的值我们也可以使用JSON.stringify,只是我们很少那样用。不过这个问题不大,我们这篇文章介绍的也是针对对象或者数组的。JSON.stringify('foo');//'"foo"'和MDN的英文版解释会更合理:JSON.stringify()方法将JavaScript对象或值转换为JSON字符串,如果指定了替换函数,则可选地替换值或如果指定了替换数组,则可选择仅包含指定的属性。简单来说,JSON.stringify()就是将值转换成对应的JSON格式字符串。JSON.stringify强大的第二个参数替换器是可选的。它可以是一个函数或一个数组。当是函数时,每个要序列化的属性都会被这个函数转换处理后,看下面代码:letreplacerFun=function(key,value){console.log(key,value)if(key==='name'){returnundefined}returnvalue}letmyIntro={name:'Gopal',age:25,like:'FE'}console.log(JSON.stringify(myIntro,replacerFun))//{"age":25,"like":"FE"}这里其实是一个过滤函数,使用JSON.stringify中undefined的属性值在序列化时会被忽略(后面会提到)。值得注意的是,一开始replacer函数会传入一个空字符串作为键值,代表要字符串化的对象。上面console.log(key,value)输出的值如下:{name:'Gopal',age:25,like:'FE'}nameGopalage25likeFE{"age":25,"like":"FE"}可以看出,通过第二个参数,我们可以更加灵活的操作和修改序列化目标的值。当第二个参数是数组时,只会序列化这个数组中包含的属性名:JSON.stringify(myIntro,['name'])//见{"name":"Gopal"}中未使用的第三个参数指定用于缩进的空白字符串,更多时候它指定一个代表几个空格的数字:letmyIntro={name:'Gopal',age:25,like:'FE'}console.log(JSON.stringify(myIntro))(JSON.stringify(myIntro,null,2))//{"name":"Gopal","age":25,"like":"FE"}//{//"name":"Gopal",//"age":25,//"like":"FE"//}JSON.stringify使用场景判断对象/数组值是否相等leta=[1,2,3],b=[1,2,3];JSON.stringify(a)===JSON.stringify(b);//truelocalStorage/sessionStorage存储对象我们知道localStorage/sessionStorage只能存储字符串,当我们要存储一个对象时,我们需要先用JSON.stringify把它转成字符串,拿到之后再用JSON.parse。//保存函数setLocalStorage(key,val){window.localStorage.setItem(key,JSON.stringify(val));};//获取函数getLocalStorage(key){letval=JSON.parse(window.localStorage.getItem(钥匙));返回值;};实现对象深度复制letmyIntro={name:'Gopal',age:25,like:'FE'}functiondeepClone(){returnJSON.parse(JSON.stringify(myIntro))}letcopyMe=deepClone(myIntro)copyMe.like='Fitness'console.log(myIntro,copyMe)//{name:'Gopal',age:25,like:'FE'}{name:'Gopal',age:25,like:'Fitness'}路由(浏览器地址)参数传递因为浏览器参数传递只能通过字符串来完成,所以还需要JSON.stringify。JSON.stringify使用注意事项看完以上,是不是觉得JSON.stringify很强大,想马上在项目中试用一下呢?稍等一下,阅读以下注意事项后再做决定,在某些场景下可能会引发一些难以发现的问题。转换后的属性值中有一个toJSON方法。如果转换后的值中有toJSON方法,则该方法返回的值就是最终的序列化结果。//toJSONlettoJsonMyIntro={name:"Gopal",age:25,like:"FE",toJSON:function(){return"Frontendgrocerystore";},};console.log(JSON.stringify(toJsonMyIntro));//“Front-endGroceryStore”的转换值中存在未定义、任意函数、符号值。两种情况慎用:一种是数组对象,未定义、任意函数、符号值都会被转为null。JSON.stringify([undefined,Object,Symbol("")]);//'[null,null,null]'为非数组对象,在序列化时会被忽略。JSON.stringify({x:undefined,y:Object,z:Symbol("")});//'{}'对于这种情况,我们可以使用JSON.stringify的第二个参数,使其符合我们的预期consttestObj={x:undefined,y:Object,z:Symbol("test")}constresult=JSON.stringify(testObj,function(key,value){if(value===undefined){返回'undefined'}elseif(typeofvalue==="symbol"||typeofvalue==="function"){returnvalue.toString()}returnvalue})console.log(resut)//{"x":"undefined","y":"functionObject(){[nativecode]}","z":"Symbol(test)"}包含循环引用的对象,谨慎使用letobjA={name:"Gopal",}letobjB={age:25,}objA.age=objBobjB.name=objAJSON.stringify(objA)会报如下错误:UncaughtTypeError:ConvertingcircularstructuretoJSON-->startingatobjectwithconstructor'Object'|property'age'->objectwithconstructor'Object'---property'name'在JSON.stringify(
