JSON은 Infinity와 NaN을 제외했습니다. ECMAScript의 JSON 상태?


180

JSON이 왜 NaN 및 +/- Infinity를 생략했는지 알고 있습니까? NaN 또는 +/- 무한대 값을 포함하는 경우 직렬화 가능한 객체가 아닌 이상한 상황에 Javascript를 배치합니다.

이것은 돌로 캐스팅 된 것 같습니다 : RFC4627ECMA-262 참조 (마지막 편집시 ECMA-262 pdf 683 페이지 24.5.2, JSON.stringify, 참고 4, 683 페이지 참조) :

유한 번호는을 호출하여 마치 문자열로 표시됩니다 ToString(number). 부호에 관계없이 NaN 및 Infinity는 String으로 표시됩니다 null.


어느 문서에서나 그 견적을 찾을 수 없습니다.
wingedsubmariner

1
그것을 고쳤습니다, 어떻게 든 오래된 참조 / 오래된 편집이있는 것처럼 보입니다.
Jason S

답변:


90

Infinity그리고 NaN하지 키워드 또는 아무것도 특별하다, 그들은 단지 전역 객체의 속성 (있는 그대로이다 undefined)와 같은이 변경 될 수있다. 당신이 경우에 진정한 JSON 문자열이 ECMA 스크립트에서 같은 결과가 있어야 본질적으로 - 그것은 JSON은 사양에 포함하지 않는 이유입니다 eval(jsonString)JSON.parse(jsonString).

그것이 허용되면 누군가가 비슷한 코드를 주입 ​​할 수 있습니다

NaN={valueOf:function(){ do evil }};
Infinity={valueOf:function(){ do evil }};

포럼 (또는 무엇이든)으로 연결 한 다음 해당 사이트의 모든 json 사용법이 손상 될 수 있습니다.


29
1/0을 평가하면 Infinity가되고, -1/0을 평가하면 -Infinity가되고, 0/0을 평가하면 NaN이됩니다.
Jason S

9
그러나 용어 NaNInfinity속성 이름이므로 String (1/0)은 "Infinity"값 무한대의 문자열 표현 인 문자열 을 생성합니다 . 이 대표 할 수 없습니다 중 하나 NaN또는 Infinity리터럴 값은 ES처럼 - 당신도 식 (. 예를 들어, 1/0, 0/0 등) 또는 속성 조회 (참조 사용할 필요가 Infinity또는 NaN). 코드 실행이 필요하므로 JSON에 포함될 수 없습니다.
olliej

16
안전 / 보안에 대한 요점으로 NaN을 변환 할 때 수행해야 할 모든 JSON 파서는 수행해야 할 모든 값에 관계없이 "실제"NaN을 반환하는 값 0/0 (심볼 NaN을 평가하는 대신)을 산출하는 것입니다 NaN 기호는 다음과 같이 재정의됩니다.
Jason S

33
@ olliej : NaN이 리터럴이 아니라고 주장합니다 .Javascript 시맨틱을 판단하기에 충분한 Javascript를 모르겠습니다. 그러나 배정도 부동 소수점 숫자를 저장하는 파일 형식의 경우 리터럴 NaN / Infinity / NegInfinity와 같이 IEEE 부동 소수점을 정의하는 방법이 있어야합니다. 이것은 64 비트 복식의 상태이므로 표현 가능해야합니다. 그들에게 의존하는 사람들이 있습니다 (이유로). JSON / Javascript가 과학 컴퓨팅 대신 웹 개발에서 시작 되었기 때문에 아마도 잊었을 것입니다.
wirrbel

35
JSON이 NaN, Infinity 및 -Infinity의 완벽하게 유효한 표준 부동 소수점 숫자 상태를 임의로 생략 한 것은 100 %이며 절대적으로 잘못되었습니다. 기본적으로 JSON은 IEEE float 값의 임의의 하위 집합을 지원하기로 결정했습니다. 세 가지 특정 값은 어렵 기 때문에 무시합니다. 아니요. 이러한 숫자는 리터럴 1/0, -1/0 및 0/0으로 인코딩 될 수 있기 때문에 평가 가능성은 변명조차되지 않습니다. "/ 0"이 추가 된 유효한 숫자로, 탐지하기 쉬울뿐만 아니라 실제로 ES로 평가할 수 있습니다. 변명하지.
Triynko

56

원래 질문에 따르면 : 이것은 JSON에서 불행한 누락이라는 점에서 사용자 "cbare"에 동의합니다. IEEE754는이를 부동 소수점 숫자의 세 가지 특수 값으로 정의합니다. 따라서 JSON은 IEEE754 부동 소수점 숫자를 완전히 나타낼 수 없습니다. ECMA262 5.1에 정의 된 JSON은 해당 숫자가 IEEE754를 기반으로하는지 여부를 정의하지 않기 때문에 실제로 더 나쁩니다. ECMA262의 stringify () 함수에 대해 설명 된 설계 흐름은 세 가지 특수 IEEE 값을 언급하므로 실제로 IEEE754 부동 소수점 숫자를 지원하려는 의도 일 수 있습니다.

XML 데이터 유형 xs : float 및 xs : double은 IEEE754 부동 소수점 숫자를 기반으로하며 이러한 세 가지 특수 값의 표현을 지원한다는 질문과 관련이없는 다른 데이터 요소 중 하나입니다 (W3C XSD 1.0 Part 2 참조). , 데이터 유형).


5
나는 이것이 불행한 것에 동의합니다. 그러나 JSON 숫자가 정확한 부동 소수점 형식을 지정하지 않는 것이 좋습니다. IEEE754조차도 다양한 형식, 크기 및 소수와 이진 지수의 구분을 지정합니다. JSON은 특히 10 진수에 매우 적합하므로 일부 표준에서 이진수로 고정하는 것이 유감입니다.
Adrian Ratnapala

5
@AdrianRatnapala +1 실제로 : JSON 숫자는 잠재적으로 무한 정밀도를 가지므로 크기 제한, 정밀도 제한 및 반올림 효과가 없기 때문에 IEEE 사양보다 훨씬 낫습니다 (직렬화 기가 처리 할 수있는 경우).
Arnaud Bouchez

2
@ArnaudBouchez. 즉, JSON은 여전히 ​​NaN 및 + -Infinity를 나타내는 문자열을 지원해야합니다. JSON을 IEEE 형식으로 고정하지 않아도 숫자 형식을 정의하는 사람들은 최소한 위키 백과 페이지 IEEE754를보고 생각하는 것을 멈추어야합니다.
Adrian Ratnapala


불행하지 않습니다. @CervEd의 답변을 참조하십시오. IEE754에 묶여 있지는 않습니다 (대부분의 프로그래밍 언어가 IEEE754를 사용하므로 NaN 등의 경우 추가 처리가 필요한 경우에도).
Ludovic Kuty

16

null 객체 패턴을 적용하고 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에서는 그러한 것을 구현하기 위해 직렬화 메소드를 대체 할 수 있다는 것을 알고 있습니다. 직렬화 위치를 잘 모르므로 직렬화 메소드에서 구현하는 방법에 대한 세부 정보를 제공 할 수 없습니다.


1
흠 ... 그것은 해결책에 대한 답변입니다. 나는 실제로 해결 방법을 요구하지 않고 왜이 가치들이 배제되었는지에 대한 질문이었습니다. 그러나 어쨌든 +1.
Jason S

2
@Zoidberg : undefined키워드가 아닙니다. 전역 객체의 속성입니다
olliej

2
@Zoidberg : undefined는 전역 객체의 속성입니다. 키워드가 아니므 "undefined" in this로 전역 범위에서 true를 반환합니다. 또한 당신이 할 수 undefined = 42있고 if (myVar == undefined)(필수적으로) 될 수 있음을 의미합니다 myVar == 42. 이것은 undefined기본적으로 존재하지 않는 ecmascript nee javascript의 초기 시절로 거슬러 올라가 므로 사람들 var undefined은 전 세계적으로 사용했습니다. 결과적으로 undefined기존 사이트를 손상시키지 않으면 서 키워드를 만들 수 없었기 때문에 우리는 정의되지 않은 속성을 가진 것으로 판명되었습니다.
olliej

2
@ olliej : undefined가 전역 객체의 속성이라고 생각하는 이유를 모르겠습니다. 기본적으로 undefined의 조회는 undefined의 기본 제공 값입니다. "undefined = 42"로 재정의하면 undefined를 변수 조회로 액세스하면 재정의 된 값을 얻게됩니다. 그러나 "zz = undefined; undefined = 42; x = {}; 'undefined old ='+ (xa === zz) + ', undefined new ='+ (xa === undefined)"를 시도하십시오. 심볼 조회를 재정의 할 수있는 경우에도 null, undefined, NaN 또는 Infinity의 내부 값을 재정의 할 수 없습니다.
Jason S

2
@Jason undefined은 이와 같이 지정되어 있기 때문에 전역 속성입니다. ECMAScript-262 3rd ed의 15.1.1.3을 참조하십시오.
kangax

11

"Infinity", "-Infinity"및 "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"}"

1
0/0 등은 유효한 JSON이 아닙니다. 표준의 범위 내에서 작업해야하며 문자열이 잘 작동합니다.
teh_senaus

반대로, 이것이 유일한 실용적인 해결책이라고 생각하지만 입력 값이 "NaN"인 경우 NaN을 반환하는 함수를 수행합니다. 변환을 수행하는 방식은 코드 삽입에 취약합니다.
Marco Sulla 10

3
JSON 값은 산술 식 표현이 될 수 없습니다. 언어 리터럴 구문과 표준을 구분하는 목표는 JSON을 코드로 실행하지 않고 역 직렬화하는 것입니다. 확실하지 왜 우리는이 없습니다 NaNInfinity같은 키워드 값으로 추가 true하고 false있지만.
Mark Reed

보다 명확하게하기 위해 다음 과 같이 사용할 수 있습니다 Number("Infinity").Number("-Infinity")Number("NaN")
HKTonyLee

이것은 마술처럼 작동합니다. 자바 스크립트로 JSON.parse("{ \"value\" : -1e99999 }")쉽게 반환 { value:-Infinity }됩니다. 이보다 더 큰 사용자 정의 숫자 유형과는 호환되지 않습니다
Thaina

7

직렬화 코드에 액세스 할 수있는 경우 무한대를 1.0e + 1024로 나타낼 수 있습니다. 지수가 너무 커서 이중으로 표현할 수 없으며 역 직렬화 할 때 무한대로 표시됩니다. 웹킷에서 작동하며 다른 json 파서에 대해 확신이 없습니다!


4
1.0e5000 더 나은 그래서 IEEE754는 128 비트 부동 소수점 숫자를 지원
톤 Plomp

2
톤 : 나중에 128 비트가 추가되었습니다. 256 비트를 추가하기로 결정하면 어떻게됩니까? 그런 다음 0을 더 추가해야하며 기존 코드는 다르게 동작합니다. Infinity항상 것입니다 Infinity, 왜 그것을 지원하지 않습니까?
날으는 양

1
영리한 아이디어! 방금 다른 형식으로 전환하거나 성가신 해결 방법 코드를 파서에 추가하려고했습니다. 모든 경우에 이상적이지는 않지만 제 경우에는 무한대가 수렴 시퀀스에 대해 최적화 된 엣지 케이스 역할을하는 완벽한 경우이며, 더 큰 정밀도가 도입 되더라도 여전히 정확합니다. 감사!
또는 Sharir

3
1, -1 및 0 ..... 완벽하게 유효한 / 파싱 가능한 숫자는 단순히 /0그 끝에 추가 할 때이 세 가지 특수 값 이됩니다. 쉽게 파싱 가능하고 즉시 표시되며 평가할 수 있습니다. 아직 표준에 추가하지 않은 것은 변명 할 수 없습니다. {"Not A Number":0/0,"Infinity":1/0,"Negative Infinity":-1/0} << 왜 그렇지 않습니까? alert(eval("\"Not A Number\"") //works alert(eval("1/0")) //also works, prints 'Infinity'. 변명하지.
Triynko


1

현재 IEEE Std 754-2008에는 두 개의 서로 다른 64 비트 부동 소수점 표현 (십진수 64 비트 부동 소수점 유형 및 이진 64 비트 부동 소수점 유형)에 대한 정의가 포함되어 있습니다.

반올림 후 문자열 .99999990000000006.9999999IEEE 이진 64 비트 표현 과 동일 하지만 IEEE 10 진수 64 비트 표현 과 동일 하지 않습니다.9999999 . 64 비트 IEEE 10 진수 부동 소수점에서는 소수점 값 과 같지 않은 .99999990000000006값으로 반올림 합니다..9999999000000001.9999999

JSON은 숫자 값을 10 진수의 숫자 문자열로 취급하기 때문에 IEEE 2 진 및 10 진 부동 소수점 표현 (예 : IBM Power)을 모두 지원하는 시스템에서 두 가지 IEEE 숫자 부동 소수점 값 중 어느 것이 예정된.


이것이 질문과 어떤 관련이 있습니까? (무한대와 NaN에 관한)
Bryan

1

{ "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 표현으로 다시 바꾸는 것입니다.


솔직히 JSON 문자열에 Infinity 또는 IsNaN 값이 포함 된 상황에 직면하면 구문 분석하려고하면 실패 할 수 있기 때문에이 솔루션이 다운 투표를 얻은 이유를 모르겠습니다. 이 기술을 사용하여 먼저 IsNaN 또는 Infinity 발생을 다른 것으로 대체하고 (해당 용어를 포함 할 수있는 유효한 문자열과 분리) JSON.parse (string, callback)를 사용하여 올바른 JavaScript 값을 리턴하십시오. 프로덕션 코드에서 이것을 사용하고 있으며 아무런 문제가 없었습니다.
SHamel

이것이 문자열 내부의 무한대를 망치지 않습니까? 많은 유스 케이스의 경우 문제가 아니라고 가정하는 것이 안전하지만 솔루션이 완전히 강력하지는 않습니다.
olejorgenb

1

이유는 표준 ECMA-404 ii 페이지 JSON 데이터 교환 구문, 1 판에 나와 있습니다.

JSON은 숫자를 무시합니다. 모든 프로그래밍 언어에는 다양한 수의 다양한 용량 및 보완, 고정 또는 부동, 이진 또는 십진수가있을 수 있습니다. 다른 프로그래밍 언어 사이의 교환을 어렵게 만들 수 있습니다. 대신 JSON은 사람이 사용하는 숫자의 표현, 즉 일련의 숫자 만 제공합니다. 모든 프로그래밍 언어는 내부 표현에 동의하지 않더라도 숫자 시퀀스를 이해하는 방법을 알고 있습니다. 교환이 가능합니다.

많은 인해의 표현에, 주장 그 이유는,하지 NaNInfinityECMA 스크립트. 단순성은 JSON의 핵심 설계 원칙입니다.

너무 간단하기 때문에 JSON 문법이 바뀌지 않을 것으로 예상됩니다. 이것은 JSON을 기본 표기법으로 제공하여 엄청난 안정성을 제공합니다.


-3

나와 같이 직렬화 코드를 제어 할 수없는 경우 NaN 값을 다음과 같이 해킹 비트로 null 또는 다른 값으로 대체하여 NaN 값을 처리 할 수 ​​있습니다.

$.get("file.json", theCallback)
.fail(function(data) {
  theCallback(JSON.parse(data.responseText.replace(/NaN/g,'null'))); 
} );

본질적으로, 원래 json 파서가 유효하지 않은 토큰을 감지하면 .fail이 호출됩니다. 그런 다음 문자열 교체를 사용하여 유효하지 않은 토큰을 교체합니다. 필자의 경우 serialiser가 NaN 값을 반환하는 것은 예외 이므로이 방법이 가장 좋습니다. 결과에 일반적으로 유효하지 않은 토큰이 포함되어 있으면 $ .get을 사용하지 않고 JSON 결과를 수동으로 검색하고 항상 문자열 대체를 실행하는 것이 좋습니다.


21
영리하지만 완전히 바보는 아닙니다. 함께 사용해보십시오{ "tune": "NaNaNaNaNaNaNaNa BATMAN", "score": NaN }
JJJ

1
jQuery를 사용해야합니다. $ .get ()이 없습니다.
Jason S
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.