从10多年前JSON在线编辑器的早期开始,用户经常反映编辑器有时会破坏他们JSON文档中的大数字的问题。直到现在,我们也没能解决这个问题。在这篇文章中,我们深入解释了这个问题,并展示如何在JSON Editor Online中解决这个问题。
大多数 Web 应用程序处理来自服务器的数据。这些数据以纯文本的JSON文档形式被接收,并被解析成一个JavaScript对象或数组,这样我们就可以读取属性并做一些事情。通常情况下,数据的解析是使用JSON.parse
函数进行的,该函数内置于JavaScript中,非常快速和方便。
JSON数据格式极其简单,而且它是JavaScript的一个子集。所以它与JavaScript完全可以互换。你可以将一个JSON文档粘贴到一个JavaScript文件中,这就是有效的JavaScript。
在JavaScript中使用JSON
应该不会出现任何问题,但有一种棘手的情况可能会破坏数据:大数字。这是一个有效的JSON字符串:
{"count": 9123372036854000123}
当我们将其解析为JavaScript并读取 "count"
键时,我们会得到:
9123372036854000000
解析后的数值被破坏了:最后三位数字被重置为零。这是否是一个问题,取决于这些最后的数字是否确实有意义,但一般来说,知道这种情况可能会发生,可能会给你一种不舒服的感觉。
像 9123372036854000123
这样的长数字既是有效的 JSON 也是有效的 JavaScript。当JavaScript 将数值解析为数字时,事情就出错了。最初,JavaScript 只有一种数字类型。Number
。这是一个64位的浮点值,类似于C++、Java或C#中的Double值。这种浮点值可以存储大约16位数字。因此,它不能完全代表像9123372036854000123
这样的数字,它有19位数字。在这种情况下,最后三位数字会丢失,破坏了该值。
在用浮点数存储分数时也会发生同样的情况:当你在 JavaScript 中计算 1/3
时,结果是:
0.3333333333333333
在现实中,该值应该有无限的小数,但 JavaScript 的数字在大约 16位 之后就停止了。
那么,JSON文档中像9123372036854000123
这样的大数字是怎么来的呢?嗯,其他语言如Java或C#确实有其他数字数据类型,如Long。Long是一个64
位的值,可以容纳最多20位的整数。它能容纳更多数字的原因是,它不需要像浮点值那样存储指数值。因此,在像Java这样的语言中,你可以有一个Long值,它不能在JavaScript的Number类型中正确表示,或者在其他语言中的Double类型中正确表示。
JavaScript 的 Number(或者更好:任何浮点数值)还有一些限制:数值可以溢出或下溢。例如,1e+500
会变成Infinity
,而1e-500
会变成0
。不过,这些限制在实际应用程序中很少成为问题。
多年来,这个用 JavaScript 解析大数字的问题一直是https://jsoneditoronline.org/
的用户反复要求的。像大多数基于网络的JSON编辑器一样,它也使用了本地的JSON.parse函数和常规的JavaScript数字,所以它受到了上述的限制。
第一个想法可能是:等等,但是 JSON.parse
有一个可选的reviver
参数,允许你用不同的方式来解析内容。但问题是,首先文本被解析成一个数字,接下来,它被传递给reviver
。所以到那时,已经太晚了,值已经被破坏了。
为了解决这个问题,根本不能使用内置的JSON.parse
,必须使用一个不同的JSON解析器。对此有各种优秀的解决方案:lossless-json、json-bigint、js-jon-bigint或json-source-map。
这些库中的大多数都采取了务实的方法,将长数字直接解析为JavaScript相对较新的BigInt数据类型。lossless-json
库是专门为JSON Editor Online开发的。它采取了比JSON BigInt解决方案更加灵活和强大的方法。
默认情况下,lossless-json 将数字解析成一个轻量级的LosslessNumber
类,该类将数字值作为一个字符串持有。这保留了任何数值,甚至还保留了格式化,比如数值4.0
中的尾部零。当对其进行操作时,LosslessNumber
将被转换为Number
或BigInt
,或者在不安全时抛出一个错误。
该库允许你传递你自己的数字解析器,所以你可以应用你自己的策略来处理数字值。也许你想把长的数字值转换成BigInt,或者把数值传给某个BigNumber
库。你可以选择是否要在数字信息丢失时抛出一个异常,或者默默地忽略某些类别的信息丢失。
因此,比较本地JSON.parse
函数和lossless-json
,会得到以下结果:
import { parse, stringify } from 'lossless-json'
const text = '{"decimal":2.370,"long":9123372036854000123,"big":2.3e+500}'
// JSON.parse will lose some digits and a whole number:
console.log(JSON.stringify(JSON.parse(text)))
// '{"decimal":2.37,"long":9123372036854000000,"big":null}'
// WHOOPS!!!
// LosslessJSON.parse will preserve all numbers and even the formatting:
console.log(stringify(parse(text)))
// '{"decimal":2.370,"long":9123372036854000123,"big":2.3e+500}'
答案是并不能。这取决于你在解析数据后想做什么,但通常情况下,你想用它做一些事情。在屏幕上显示数据,验证它,比较它,排序它,等等。例如,在JSON Editor Online中,你可以编辑数值,转换文档(查询、过滤、排序等),比较两个文档,或者根据JSON模式验证一个文档。一旦你引入BigInt值或LosslessNumbers,你想执行的所有操作都需要支持这些类型的值。
拥有 BigInt 值或 LosslessNumbers 的数据很可能给不了解这些数据类型的第三方库带来问题。例如,JSON Editor Online支持将你的JSON数据导出到CSV,并使用优秀的json2csv库来实现。
这个库不知道BigInt
或LosslessNumber
类型,不会正确串联这些数据类型。为了使其正常工作,包含LosslessNumbers
或BigInt
值的JSON数据必须首先被转换为该库所能理解的数据。
即使没有第三方库的参与,与BigInt值一起工作也会导致棘手的问题。当对大整数和普通数字的混合操作时,JavaScript可以默默地将一种数字类型强制转化为另一种,这可能会导致错误。下面的代码例子显示了这是如何出错的。
const a = 91111111111111e3 // a regular number
const b = 91111111111111000n // a bigint
console.log(a == b) // returns false (should be true)
console.log(a > b) // returns true (should be false)
在这个例子中,你看到两个常数a
和b
持有相同的数字值。但是一个是数字,另一个是BigInt,用这些东西和普通的操作符(如==
和>
)一起使用会导致错误的结果。
结论:要让大数字在一个应用程序中工作,可能需要大量的努力。因此,最好的办法是尽量避免在一开始就处理这些问题。
如果你真的要处理大数值,你必须使用一个替代的JSON分析器,如lossless-json
。为了防止陷入与拥有BigInt
或LosslessNumber
数据类型有关的难以调试的问题,使用TypeScript明确定义你的数据模型是很有帮助的。这样,你就可以事先知道哪些地方需要能够处理这些特殊的数据类型,你就可以采取行动,而不是让你的应用程序默默地失败。
从今天起,JSON Editor Online已经完全支持大数字,所以你不必再担心损坏的数值。它已经集成了lossless-json
库,并确保编辑器的所有功能都能处理大数字:从格式化、排序和查询到导出到CSV。作为一个副作用,它现在甚至保持了数字的格式化,而且由于新的LosslessJSON
解析器,现在可以检测到重复的键。
试一试:https://jsoneditoronline.org/#left=json.%7B%20%22using%22:%20%22Lossless%20JSON%20Parser%22,%20%22formatted%20number%22:%204.0,%20%22long%22:%209123372036854000123,%20%22large%22:%201e500,%20%22small%22:1e-500%20%7D
现在,使用lossless-json
有一个缺点:它比原生内置的JSON.parse
慢得多。这只是大的JSON对象或数组的问题,对于大于10MB的文件,它可能会很明显。为了仍能顺利地处理大文件,JSON Editor Online允许你选择你想使用的解析器,默认情况下,它会自动为你选择最合适的解析器。
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/rFyA0Pnk7_y3rgYmjzE4sQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。