На самом деле существует ограничение на уровне точности JavaScript/ECMAScript до 53 бит для целых чисел (они хранятся в мантиссе двойного буфера памяти размером 8 байт). Таким образом, передача больших чисел в формате JSON не будет десериализована, как ожидается клиентом JavaScript, который усекает их до 53-битного разрешения.
> parseInt("10765432100123456789")
10765432100123458000
См. Number.MAX_SAFE_INTEGER
константа и Number.isSafeInteger()
функция:
Константа MAX_SAFE_INTEGER
имеет значение 9007199254740991
. Причина этого числа заключается в том, что JavaScript использует числа формата с плавающей запятой двойной точности, как указано в IEEE 754, и может безопасно представлять только числа между -(2^53 - 1)
и 2^53 - 1
.
Безопасный в этом контексте относится к способности точно представлять целые числа и правильно их сравнивать. Например, Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2
будет равно true
, что математически неверно. См. Number.isSafeInteger()
для получения дополнительной информации.
Из-за разрешения поплавков в JavaScript использование 64-битных чисел с плавающей запятой, как вы предложили, будет страдать от того же ограничения.
ИМХО лучший вариант - передавать такие значения как текст. Это будет по-прежнему прекрасно читаемый контент JSON, и с ним будет легко работать на уровне JavaScript.
Чистое строковое представление — это то, что задает OData для своих типов Edm.Int64
или Edm.Decimal
.
Что делает Twitter API в этом случае, так это добавляет конкретное поле ".._str":
в JSON, как таковое:
{
"id": 10765432100123456789, // for JSON compliant clients
"id_str": "10765432100123456789", // for JavaScript
...
}
Мне очень нравится этот вариант, так как он по-прежнему совместим с клиентами с поддержкой int64. На практике такой дублированный контент в JSON не сильно повредит, если его сдуть/заархивировать на уровне HTTP.
После передачи в виде строки вы можете использовать такие библиотеки, как strint — библиотека JavaScript для строковых целых чисел для обработки такие ценности.
Обновление. Новые версии движков JavaScript включают BigInt объектный класс, способный обрабатывать более 53-бит. На самом деле его можно использовать для произвольно больших целых чисел, поэтому он хорошо подходит для 64-битных целых чисел. Но при сериализации в формате JSON значение BigInt будет сериализоваться как строка JSON - как ни странно, но я думаю, в целях совместимости.
person
Arnaud Bouchez
schedule
25.01.2016