JSON。stringify是我们经常用到的的一个方法,它主要作用是将JavaScript值和对象转换为字符串。如:JSON。stringify({foo:bar});{foo:bar}JSON。stringify(123);123 但是JS的许多地方都有问题,这个函数也不例外。我们可能会想象一个叫做stringify的函数总是返回一个字符串。。。。。。但它并没有! 例如,如果你尝试stringifyundefined,它返回undefined,而不是一个字符串。JSON。stringify(undefined);undefined 接下来,我将分两部分讲:列举JSON。stringify不返回字符串的情况我们将如何避免这些陷阱什么时候JSON。stringify不返回字符串? undefined、任意的函数以及symbol值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成null(出现在数组中时)。函数、undefined被单独转换时,会返回undefined。 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误 我认为JSON。stringify能够返回字符串以外的东西是挺惊讶的。但在6种情况下,它可以返回undefined:试图在顶层对undefined进行序列化,会返回undefined。JSON。stringify(undefined);undefined尝试序列化函数也会返回undefined。对于常规函数、箭头函数、异步函数和生成器函数都是如此。JSON。stringify(functionfoo(){});undefinedJSON。stringify((){});undefinedfunctionbar(){}bar。someProperty123;JSON。stringify(bar);undefined尝试序列化symbol也会返回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:stringJSON。stringify(undefined); 在第2部分中,我们将讨论如何更新TypeScript的定义以确保其正确性。 JSON。stringify也可能遇到问题,导致它抛出一个错误。在正常情况下,有四种情况会发生:循环引用会导致抛出一个类型错误。constb{a};a。JSON。stringify(a);TypeError:cyclicobjectvalue 注意,这些错误消息在不同浏览器可能提示是不样的,例如,Firefox的错误信息与Chrome的不同。BigInts不能用JSON。stringify进行序列化,这些也会导致一个TypeError。JSON。stringify(12345678987654321n);TypeError:BigIntvaluecantbeserializedinJSONJSON。stringify({foo:456n});TypeError:BigIntvaluecantbeserializedinJSON带有toJSON函数的对象将被运行。如果这些函数抛出错误,它将冒泡到调用者。constobj{foo:ignored,toJSON(){thrownewError(Ohno!);},};JSON。stringify(obj);Error:Ohno!你可以传递第二个参数,称为replacer。如果这个函数抛出一个错误,它将冒泡。JSON。stringify({},(){thrownewError(Uhoh!);});Error:Uhoh! 现在我们已经看到了JSON。stringify不返回字符串的情况,接下来,我们来看看如何避免这些问题。如何避免这些问题 没有关于如何解决这些缺陷的通用方法,所以这里只介绍一些常见的情况。处理循环引用 根据个人经验,JSON。stringify在传递循环引用时最容易出错。如果这对你来说是一个常见的问题,我推荐jsonstringifysafe包,它能很好地处理这种情况。conststringifySaferequire(jsonstringifysafe);consta{};constb{a};a。JSON。stringify(a);TypeError:cyclicobjectvaluestringifySafe(a);{b:{a:〔Circular〕}}封装 你可能想用你自己的自定义函数来封装JSON。stringify。你可以决定你想要它做什么。错误应该冒出来吗?如果JSON。stringify返回undefined,应该怎么做? 例如,SignalDesktop有一个名为reallyJsonStringify的函数,它总是返回一个用于调试的字符串。就像这样functionreallyJsonStringify(value){try{resultJSON。stringify(value);}catch(err){Iftheresanyerror,treatitlikeundefined。}if(typeofresultstring){Itsastring,soweregood。}else{Convertittoastring。returnObject。prototype。toString。call(value);}}关于TypeScript类型的说明 如果你已经在用TypeScript,可能会惊讶地发现,TypeScript对JSON。stringify的官方定义在这里并不正确。它们实际上看起来像这样:Note:这里面简化过interfaceJSON{。。。stringify(value:any):} 不幸的是,这是一个长期存在的问题,没有一个完美的解决方案。 你可以尝试修补JSON。stringify的类型,但每个解决方案都有一定的缺点。我建议用自定义类型定义自己的包装器并。例如,SignalDesktop的reallyJsonStringify的模板:functionreallyJsonStringify(value:unknown):string{。。。总结JSON。stringify有时会返回undefined,而不是一个字符串JSON。stringify有时会抛出一个错误我们可以通过用不同的方式包装函数来解决这个问题 希望这篇文章能让你对JSON。stringify有更全面的了解。 我是刷碗智,励志退休后要回家摆地摊的人,我们下期见。 作者:BlackLivesMatter译者:前端小智来源:devinduct原文:https:evanhahn。comwhenstringifydoesntreturnastring