js处理Json中的长整数

26. 10 月 2017 JavaScript 0

在前端页面展示数据的时候,通常都需要处理来自后端的json数据。通常这个过程都是非常简单的,比如通过jQuery的ajax(或者更暴力的getJSON)。但是如果服务器传来的json中包含一个很大的整数,如 {"v": 123456789123456789123} ,那么接受后会发现变成了 {v: 123456789123456800000} 。

问题原因

js是弱类型语言,所有的数字类型统称为Number类型,不区分int、long、double等。而Number是根据IEEE 754的double来实现的,即所有的Number类型都是64位双精度实型。sf上提供了一个对IEEE 574非常友好的讲解,这里不再赘述。在文章中也提到了NUMBER.MAX_SAFE_INTEGER的计算方法,是9007199254740991,所有大于这个数的整数都会损失精度。

可行的解决方案

  1. 最直接的,让服务端传数据的时候,把超长的字段强转成string。但是如果服务端类型敏感,且比较复杂的时候,通常不太想这么搞。
  2. 前端实现一个json parser。

制作json parser

在服务端开发中,通常使用bison可以定制json parser(在fp中则更简单),js中有没有类似bison的工具呢?有——jison,号称“bison in javascript”,通过npm可以安装,不过他的文档地址似乎不太对,需要访问这里。好在功能上用起来还是没啥问题的。

npm install jison 之后,在 lib 目录下提供了 cli.js 来生成我们的parser。参数有两个(通常情况,有很多我们不太需要,详见cli.js代码), cli.js grammaFile lexFile ,grammaFile是语法文件,lexFile是词表文件。

下面就是怎么写这两个文件了,可以通过文档来学习一下这类文件的语法。如果不想这么麻烦,还可以在jison作者的另一个项目——jsonlint里面找到,在该项目github中的src目录下提供了jsonlint.y(grammaFile)和jsonlint.l(lexFile)。使用这两个文件可以直接生成jsonlint.js,放到网页中当json parser来使用。

但是我们的目的是让一些会丢失精度的整数被保留下来,最好的方法是:当整数超过了安全范围的时候,使用字符串表示。我们可以通过修改jsonlint.y来达到这个目的。

原本对JSONNumber的定义是

在这里yytext是要进行解析的原始数据,$$是结果。我们可以修改成

就OK了。同理的,如果想把传来的string类型的数字还原成Number类型,也可以在JSONString中修改

BTW,如果想把以String方式传来的实数也还原成Number的形式,要使用类似ABS(a-b)<epsilion的方式,否则如果传过来一个”0.00000″就没办法被转换了。。。

 

然后我们在需要使用的网页上加上

就可以使用了。但是注意这句 $ = jQuery ,因为jison生成的代码中,将 $ 赋值成了其他东西,暂时还没找到无害的修改方法(jison里面代码有点难读。。),暂时我是这么用的。

 


发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据