JSON оставил Бесконечность и NaN; Статус JSON в ECMAScript?
Любая идея, почему JSON оставил NaN и +/- Infinity? Он помещает Javascript в странную ситуацию, когда объекты, которые в противном случае были бы сериализуемыми, не являются, если они содержат значения NaN или +/- бесконечности.
Похоже, что это было брошено в камень: см. RFC4627 и ECMA-262 (раздел 24.3.2, JSON.stringify, ПРИМЕЧАНИЕ 4, стр. 507 при последнем редактировании):
Конечные числа стробируются так, как если бы он вызывал ToString(number)
. NaN и бесконечность независимо от знака представлены как строка null
.
Ответы
Ответ 1
Infinity
и NaN
не являются ключевыми словами или чем-то особенным, это просто свойства глобального объекта (как undefined
) и как таковые могут быть изменены. По этой причине JSON не включает их в спецификацию - по существу, любая истинная строка JSON должна иметь тот же результат в EcmaScript, если вы делаете eval(jsonString)
или JSON.parse(jsonString)
.
Если бы это было разрешено, кто-то мог ввести код, похожий на
NaN={valueOf:function(){ do evil }};
Infinity={valueOf:function(){ do evil }};
в форум (или что-то еще), а затем любое использование json на этом сайте может быть скомпрометировано.
Ответ 2
По первому вопросу: я согласен с пользователем "cbare" в том, что это неудачное упущение в JSON. IEEE754 определяет их как три специальных значения числа с плавающей запятой. Таким образом, JSON не может полностью отображать числа с плавающей запятой IEEE754. На самом деле это еще хуже, поскольку JSON, как определено в ECMA262 5.1, даже не определяет, основаны ли его номера на IEEE754. Поскольку поток проектирования, описанный для функции stringify() в ECMA262, упоминает три специальных значения IEEE, можно предположить, что на самом деле намерение было поддерживать числа с плавающей запятой IEEE754.
Как еще одна точка данных, не связанная с вопросом: XML-типы данных xs: float и xs: double делают так, что они основаны на числах с плавающей запятой IEEE754, и они поддерживают представление этих трех специальных значений (см. W3C XSD 1.0 Part 2, Datatypes).
Ответ 3
Не можете ли вы адаптировать шаблон нулевого объекта, а в JSON - такие значения, как
"myNum" : {
"isNaN" :false,
"isInfinity" :true
}
Затем при проверке вы можете проверить тип
if (typeof(myObj.myNum) == 'number') {/* do this */}
else if (myObj.myNum.isNaN) {/* do that*/}
else if (myObj.myNum.isInfinity) {/* Do another thing */}
Я знаю, что в Java вы можете переопределить методы сериализации, чтобы реализовать такую вещь. Не уверен, где вы выполняете сериализацию, поэтому я не могу описать, как ее реализовать в методах сериализации.
Ответ 4
Это может быть связано с тем, что JSON предназначен для обмена данными, который может использоваться на различных платформах и позволяя NaN/Infinity сделать его менее портативным.
Ответ 5
Строки "Бесконечность", "-Инфинити" и "NaN" все принуждают к ожидаемым значениям в JS. Поэтому я бы сказал, что правильный способ представления этих значений в JSON - это строки.
> +"Infinity"
Infinity
> +"-Infinity"
-Infinity
> +"NaN"
NaN
Это просто позор. JSON.stringify не делает этого по умолчанию. Но есть способ:
> JSON.stringify({ x: Infinity }, function (k,v) { return v === Infinity ? "Infinity" : v; })
"{"x":"Infinity"}"
Ответ 6
Если у вас есть доступ к коду сериализации, вы можете представить Infinity как 1.0e + 1024. Показатель слишком велик, чтобы представлять в двойнике, а при десериализации это представляется как Бесконечность. Работает на webkit, не уверен в других парсерах json!
Ответ 7
В текущий IEEE Std 754-2008 включены определения для двух разных 64-битных представлений с плавающей запятой: десятичный 64-битный тип с плавающей запятой и двоичный 64-разрядный тип с плавающей запятой.
После округления строка .99999990000000006
совпадает с .9999999
в бинарном 64-битном представлении IEEE, но она не совпадает с .9999999
в десятичном 64-битном представлении IEEE. В 64-битных десятичных циклах с плавающей запятой IEEE .99999990000000006
округляется до значения .9999999000000001
, которое не совпадает с десятичным значением .9999999
.
Поскольку JSON просто обрабатывает числовые значения в виде числовых строк десятичных цифр, для системы, поддерживающей двоичные и десятичные представления с плавающей запятой IEEE (например, IBM Power), нет возможности определить, какой из двух возможных числовых плавающих чисел IEEE, точные значения.
Ответ 8
Причина указана на странице ii в стандарте ECMA-404. Синтаксис обмена данными JSON, 1-е издание
JSON не зависит от чисел. В любом языке программирования может быть множество типов чисел различной емкости и дополнения, фиксированное или плавающее, двоичное или десятичное. Это может затруднить обмен между различными языками программирования. Вместо этого JSON предлагает только представление чисел, которые используют люди: последовательность цифр. Все языки программирования знают, как понимать последовательности цифр, даже если они не согласны с внутренними представлениями. Этого достаточно, чтобы позволить обмен.
Причина, как утверждают многие, не в том, что в сценариях ECMA NaN
и Infinity
. Простота - основной принцип проектирования JSON.
Поскольку это так просто, не ожидается, что грамматика JSON когда-либо изменится. Это дает JSON, как основополагающему обозначению, огромную стабильность
Ответ 9
Потенциальный обходной путь для таких случаев, как {"key": Infinity}:
JSON.parse(theString.replace(/":(Infinity|-IsNaN)/g, '":"{{$1}}"'), function(k, v) {
if (v === '{{Infinity}}') return Infinity;
else if (v === '{{-Infinity}}') return -Infinity;
else if (v === '{{NaN}}') return NaN;
return v;
});
Основная идея состоит в том, чтобы заменить вхождения недопустимых значений строкой, которую мы распознаем при разборе, и заменить ее соответствующим представлением JavaScript.
Ответ 10
Если у вас нет контроля над кодом сериализации, вы можете иметь дело с значениями NaN, заменяя их нулевым или любым другим значением в виде взлома следующим образом:
$.get("file.json", theCallback)
.fail(function(data) {
theCallback(JSON.parse(data.responseText.replace(/NaN/g,'null')));
} );
По сути,.fail будет вызван, когда оригинальный json-парсер обнаружит недопустимый токен. Затем вместо замены недействительных токенов используется замена строки. В моем случае для сериализатора исключение возвращает значения NaN, поэтому этот метод является наилучшим подходом. Если результаты обычно содержат недопустимый токен, вам лучше не использовать $.get, а вместо этого вручную извлекать результат JSON и всегда запускать замену строки.