js处理Json中的长整数
在前端页面展示数据的时候,通常都需要处理来自后端的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,所有大于这个数的整数都会损失精度。
可行的解决方案
- 最直接的,让服务端传数据的时候,把超长的字段强转成string。但是如果服务端类型敏感,且比较复杂的时候,通常不太想这么搞。
- 前端实现一个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的定义是
1 2 3 4 5 6 |
JSONNumber : NUMBER { $$ = Number(yytext) } ; |
在这里yytext是要进行解析的原始数据,$$是结果。我们可以修改成
1 2 3 4 5 6 |
JSONNumber : NUMBER< |