作者:BlackLivesMatter译者:前端小智来源:devinduct有梦想,有干货,微信搜索【大招天下】关注这个还在洗碗的洗碗智慧在清晨。本文已收录到GitHubhttps://github.com/qq449245884/xiaozhi,里面有完整的测试站点、资料和我的一线厂商访谈系列文章。JSON.stringify是我们经常使用的一个方法,它的主要功能是将JavaScript值和对象转换成字符串。如:JSON.stringify({foo:"bar"});//=>'{"foo":"bar"}'JSON.stringify(123);//=>'123'但在JS中很多地方有问题,这个函数也不例外。我们可能会想象一个名为“stringify”的函数总是返回一个字符串……但它不会!例如,如果您尝试对undefined进行字符串化,它会返回undefined而不是字符串。JSON.stringify(undefined);//=>undefined下面我分两部分讲:?undefined、任意函数和符号值在序列化时将被忽略(出现在非数组对象的属性值中时)或转换为null(出现在数组中时)。单独转换函数,undefined时,会返回undefined。在包含循环引用(对象相互引用,形成死循环)的对象上执行该方法会抛出错误。我认为JSON.stringify可以返回字符串以外的东西是令人惊讶的。但是在6种情况下它可以返回undefined:尝试在顶层序列化undefined返回undefined。JSON.stringify(undefined);//=>undefined尝试序列化函数也会返回undefined。这适用于常规函数、箭头函数、异步函数和生成器函数。JSON.stringify(functionfoo(){});//=>undefinedJSON.stringify(()=>{});//=>undefinedfunctionbar(){}bar.someProperty=123;JSON.stringify(bar);//=>undefined尝试序列化符号也将返回undefined。JSON.stringify(Symbol("computerswereamistake"));//=>undefined在浏览器中,尝试序列化已弃用的document.all也会返回undefined。//=>undefined这只会影响浏览器,因为document.all在其他环境中不可用,例如Node。将运行具有toJSON函数的对象,而不是尝试正常序列化它们。但如果toJSON返回上述值之一,试图在顶层对其进行序列化将导致JSON.stringify返回undefined。JSON.stringify({toJSON:()=>undefined});//=>undefinedJSON.stringify({ignored:true,toJSON:()=>undefined});//=>undefinedJSON.stringify({toJSON:()=>Symbol("heya")});//=>undefined你可以传递第二个参数,叫做“replacer”,它可以改变序列化的逻辑。如果此函数为顶级返回上述值之一,JSON.stringify将返回undefined。JSON.stringify({ignored:true},()=>undefined);//=>undefinedJSON.stringify(["ignored"],()=>Symbol("hello"));//=>undefined需要注意不幸的是,其中许多事情实际上只影响顶层的序列化。比如JSON.stringify({foo:undefined}),返回字符串“{}”,这并不奇怪。我还想提一下,TypeScript的类型定义在这里是不正确的。例如下面的代码类型验证可以通过:constresult:string=JSON.stringify(undefined);在第2部分中,我们将讨论如何更新TypeScript定义以确保其正确性。JSON.stringify也可能遇到导致它抛出错误的问题。在正常情况下,可能会发生四种情况:循环引用导致抛出类型错误。constb={a};a.b=b;JSON.stringify(a);//=>TypeError:cyclicobjectvalue注意,这些错误信息在不同的浏览器中可能提示不同,比如Firefox的错误信息是一样的因为Chrome是不同的。BigInts不能用JSON.stringify序列化,这些也会导致TypeError。JSON.stringify(12345678987654321n);//=>TypeError:BigIntvaluecan'tbeserializedinJSONJSON.stringify({foo:456n});//=>TypeError:BigIntvaluecan'tserializedinJSONwithtoJSON的要运行的函数的对象。如果这些函数抛出错误,它将冒泡到调用者。constobj={foo:"ignored",toJSON(){thrownewError("哦不!");},};JSON.stringify(obj);//=>错误:哦不!您可以传递第二个参数,称为替换器。如果这个函数抛出错误,它就会冒泡。JSON.stringify({},()=>{thrownewError("Uhoh!");});//=>Error:Uhoh!现在我们已经看到JSON.stringify不返回字符串,接下来,让我们看看如何避免这些问题。如何避免这些问题对于如何解决这些陷阱没有通用的方法,所以这里有一些常见的情况。处理循环引用从个人经验来看,传递循环引用时JSON.stringify是最容易出错的。如果这对您来说是一个常见问题,我推荐json-stringify-safe包,它可以很好地处理这种情况。conststringifySafe=require("json-stringify-safe");consta={};constb={a};a.b=b;JSON.stringify(a);//=>TypeError:cyclicobjectvaluestringifySafe(a);//=>'{"b":{"a":"[Circular~]"}}'包装器您可能希望使用自己的自定义函数包装JSON.stringify。你可以决定你想要它做什么。错误应该冒出来吗?JSON.stringify返回undefined怎么办?例如,SignalDesktop有一个名为reallyJsonStringify的函数,它总是返回一个字符串用于调试。像这个函数reallyJsonStringify(value){letresult;尝试{结果=JSON.stringify(value);}catch(_err){//如果有任何错误,将其视为`undefined`。结果=未定义;}if(typeofresult==="string"){//这是一个字符串,所以我们很好。返回结果;}else{//将其转换为字符串。返回对象。原型。到字符串。调用(值);}}关于TypeScript类型的注释如果您已经在使用TypeScript,您可能会惊讶地发现TypeScript对JSON.stringify的官方定义在这里是不正确的。它们实际上看起来像这样://注意:这是简化的接口JSON{//...stringify(value:any):string;}不幸的是,这是一个长期存在的问题,没有人是完美的解决方案。您可以尝试修补JSON.stringify的类型,但每种解决方案都有某些缺点。我建议使用自定义类型和.例如SignalDesktop的reallyJsonStringify的模板:functionreallyJsonStringify(value:unknown):string{//...summaryJSON.stringify有时会返回undefined而不是字符串JSON.stringify有时会抛出错误我们可以通过不同的Wrapping函数方法解决了这个问题。希望本文能让您对JSON.stringify有更全面的了解。我是玩玩志,退休后受到启发摆地摊。下次见。代码部署后可能存在的bug,无法实时获知。事后为了解决这些bug,花费了大量的时间在日志调试上。顺便推荐一个好用的bug监控工具Fundebug。原文:https://evanhahn.com/when-str...交流有梦想,有干货,微信搜索【大千世界】关注这位凌晨还在洗碗的洗碗智慧。本文GitHubhttps://github.com/qq44924588...已收录,有完整的测试站点、资料和我的一线厂商访谈系列文章。
