1前几天写了前端FatheadFish的一篇文章《就因为JSON.stringify,我的年终奖差点打水漂了》,讲的是JSON.stringify在工程开发中的应用。在线用户不能提交表格。由于字段中JSON.stringify后的string对象缺少valuekey,导致后端parse后无法正确读取value值,进而接口系统报异常,用户无法进行下一步操作。这篇文章会详细说说JSON.stringify,带你自己写一个JSON.stringify,考察你对各种数据类型的理解深度和全局视角处理各种极端边缘情况的能力。2JSON.stringify()JSON.stringify是JSON对象中的一个方法,日常开发中经常用到。它用于将JavaScript对象或值转换为JSON字符串。如果指定了替换函数,它可以有选择地替换值,或者如果指定的替换器是一个数组,则可以选择只包含数组指定的属性。简而言之,它用于将对象转换为JSON字符串。JSON.stringify(value[,replacer[,space]])value:必填参数,需要序列化的JSON对象。replacer:可选参数。函数类型:在序列化过程中,序列化值的各个属性都会被函数转换处理;数组类型:只有包含在这个数组中的属性名才会被序列化为最终的JSONString;null或未提供:对象的所有属性都将被序列化。space:可选参数,用于控制字符串之间的间距。指定缩进的空字符串,用于美化输出(pretty-print);数字类型,表示有多少个空格;上限为10,小于1表示没有空格;对于字符串类型,当字符串长度超过10个字母时,字符串的前10个字母将被视为空格;如果为null或未提供,则不会有空格。注意:循环引用对象(对象相互引用,形成死循环)执行该方法,会抛出错误。布尔值、数字、字符串的包装对象在序列化时自动转换为对应的原始值。未定义的、任意的函数和符号值,在序列化过程中将被忽略(出现在非数组对象的属性值中时)或转换为null(出现在数组中时)。functions和undefined分别转换时,会返回undefined,如JSON.stringify(function(){})或JSON.stringify(undefined)。这就是为什么不能使用JSON.parse(JSON.stringify())深度复制具有这些类型属性的对象。Date调用toJSON()将其转换为字符串(与Date.toISOString()相同),因此它将被视为字符串。NaN和Infinity格式的数值以及null都被视为null。其他类型的对象,包括Map/Set/WeakMap/WeakSet,只序列化可枚举属性。constuser={name:"yichuan",age:18,university:"SCU"};//1.序列化对象console.log(JSON.stringify(user));//'{"name":"yichuan","age":18,"university":"SCU"}'//2.序列化基本数据类型console.log(JSON.stringify("flat"));//"flat"console.log(JSON.stringify(18));//"18"console.log(JSON.stringify(true)));//"true"console.log(JSON.stringify(null));//"null"console.log(JSON.stringify(undefined));//undefined//3.使用替换函数console.log(JSON.stringify(user,function(key,value){returntypeofvalue==="number"?666:"sixsixsix";}));//'{name:"sixsixsix",age:666,大学:"sixsixsix"}'//4.指定数组console.log(JSON.stringify(user,["name"]));//'{"name":"yichuan"}'//5.指定字符串间距console.log(JSON.stringify(user,null,2));/*{"name":"yichuan","age":18,"university":"SCU"}*///6.指定字符串间距"*"console.log(JSON.stringify(user,null,"*****"));/*{*****"name":"yichuan",*****"age":18,******"university":"SCU"}*/组织归纳:JSON.stringify输入输出基本数据类型stringstringnumberstringtypestringboolean"true"/"false"undefinedundefinednull"null"NaNandInfinity"null"symbolundefinedBigInterrorreferencedatatypefunctionundefinedArray数组中出现函数、未定义、符号string/"null"|||正则表达式|“{}”|||日期|日期的toJSON()字符串|||共同对象|如果属性值中出现function、undefined、symbol,则序列化toJSON()的返回值将被忽略。所有以symbol为属性键的属性将被完全忽略|3手动撕裂JSON.stringify()。比较麻烦,需要考虑处理各类数据,考虑各种边界条件functionstringify(data){consttype=typeofdata;//可能是对基本数据类型的处理if(type!=="object"){//判断是NaN还是Infinity还是nullif(Number.isNaN(data)||data===Infinity){return"null";}//判断可能是函数,未定义,符号类型if(type==="function"||type==="undefined"||type==="symbol"){returnundefined}//判断处理string还是valueif(type==="string"||type==="number"){return`"${data}"`}if(typeofdata==='bigint'){thrownewTypeError('DonotknowhowtoserializeaBigInt')}if(isCyclic(data)){thrownewTypeError('ConvertingcircularstructuretoJSON')}returnString(data);}else{//nullif(type==="null"){return"null"}elseif(data.toJSON&&typeofdata.toJSON==="function"){//递归returnstringify(data.toJSON);}elseif(Array.isArray(data)){constarr=[];//数组有很多种情况data.forEach((item,index)=>{//判断可能是function,undefined,symboltypeif(type==="function"||type==="undefined"||type==="符号"){arr[index]="null"}else{arr[index]=stringify(item);}});result=`"${arr}"`;returnarr.result.replace(/'/g,"");}else{//普通对象constarr=[];//遍历对象Object.keys(data).forEach((key)=>{//如果key是symbol类型,则忽略if(data[key]!=="symbol"){if(typeofdata[key]!=="undefined"&&typeofdata[key]!=="function"&&typeofdata[key]!=="symbol"){arr.push(`"${key}":stringify(data[key])`);}}})return`{${arr}}`.replace(/'/g,'"')}}}4参考文章《MDN:JSON.stringify()》《就因为JSON.stringify,我的年终奖差点打水漂了》5写于end在我们平时的开发中,JSON.stringify最常见的应用就是浅层对象的深拷贝,也就是序列化处理,但是我们在手撕代码的时候,需要考虑各种边界条件,这对于us.比较麻烦,因为面试也是对数据类型的综合考察。
