JSON ने इन्फिनिटी और NaN को छोड़ दिया; ECMAScript में JSON की स्थिति?


180

किसी भी विचार क्यों JSON NaN और +/- इन्फिनिटी छोड़ दिया? यह जावास्क्रिप्ट को अजीब स्थिति में डालता है जहां ऐसी वस्तुएं जो अन्यथा अनुक्रमिक होंगी, यदि वे NaN या +/- चौड़ाई मान नहीं हैं।

ऐसा लगता है कि पत्थर में डाला गया है: RFC4627 और ECMA-262 (धारा 24.5.2, JSON.stringify, NOTE 4, पृष्ठ 683 ECMA-262 के पीडीएफ अंतिम संपादन में देखें):

परिमित संख्याओं को इस तरह से कड़ा किया जाता है जैसे कि कॉल करके ToString(number)। साइन की परवाह किए बिना NaN और इन्फिनिटी को स्ट्रिंग के रूप में दर्शाया गया है null


मुझे वह बोली या तो दस्तावेज़ में नहीं मिली।
विंगडसुम्ब्रेनर

1
इसे तय किया, ऐसा लगता है कि किसी तरह एक बासी संदर्भ / बासी संपादित किया गया था।
जेसन एस

जवाबों:


90

Infinityऔर NaNवे कीवर्ड या कुछ विशेष नहीं हैं, वे वैश्विक ऑब्जेक्ट (जैसे हैं undefined) पर केवल गुण हैं और जैसे कि बदला जा सकता है। यह इस कारण से है कि JSON ने उन्हें कल्पना में शामिल नहीं किया है - संक्षेप में किसी भी सच्चे JSON स्ट्रिंग का EcmaScript में एक ही परिणाम होना चाहिए यदि आप eval(jsonString)या JSON.parse(jsonString)

अगर इसकी अनुमति होती तो कोई व्यक्ति कोड एंकल इंजेक्ट कर सकता था

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

एक मंच में (या जो कुछ भी) और फिर उस साइट पर किसी भी json उपयोग से समझौता किया जा सकता है।


29
यदि आप 1/0 का मूल्यांकन करते हैं, तो आप इन्फिनिटी प्राप्त करते हैं, यदि आप -1/0 का मूल्यांकन करते हैं, तो आप इनफिनिटी प्राप्त करते हैं, यदि आप 0/0 का मूल्यांकन करते हैं तो आपको NaN मिलता है।
जेसन एस

9
लेकिन शब्द NaNऔर Infinityसंपत्ति के नाम हैं, इसलिए जबकि स्ट्रिंग (1/0) एक स्ट्रिंग का उत्पादन "Infinity"करता है जो मूल्य अनंतता का सिर्फ स्ट्रिंग प्रतिनिधित्व है। NaNया तो प्रतिनिधित्व करना संभव नहीं है या Infinityशाब्दिक मूल्यों के रूप में ईएस है - आपको या तो एक अभिव्यक्ति (जैसे 1/0, 0/0 आदि) या एक संपत्ति देखने ( Infinityया करने के लिए संदर्भित NaN) का उपयोग करना होगा। चूंकि उन्हें कोड निष्पादन की आवश्यकता होती है, उन्हें JSON में शामिल नहीं किया जा सकता।

16
सुरक्षा / सुरक्षा के बारे में अपनी बात करने के लिए, सभी एक अच्छे JSON पार्सर को तब करना होगा जब वह NaN को कनवर्ट करने के लिए जाता है मान 0/0 (प्रतीक NaN का मूल्यांकन करने के बजाय) प्राप्त होता है जो "असली" NaN को लौटा देगा, चाहे जो भी हो प्रतीक NaN को नए सिरे से परिभाषित किया गया है।
जेसन एस

33
@olliej: आप तर्क देते हैं कि NaN शाब्दिक नहीं है, मुझे जावास्क्रिप्ट शब्दार्थ को आंकने के लिए जावास्क्रिप्ट पर्याप्त नहीं है। लेकिन एक फ़ाइल प्रारूप के लिए जो दोहरी परिशुद्धता फ्लोटिंग पॉइंट संख्याओं को संग्रहीत करता है, IEEE फ़्लोट्स को परिभाषित करने का एक तरीका होना चाहिए, अर्थात एक शाब्दिक NaN / Infinity / NegInfinity। ये 64 बिट डबल्स के राज्य हैं और जैसा कि प्रतिनिधित्व योग्य होना चाहिए। ऐसे लोग हैं जो उन पर निर्भर करते हैं (कारणों के लिए)। वे शायद भूल गए थे क्योंकि JSON / Javascript वैज्ञानिक कंप्यूटिंग के बजाय वेब विकास में उत्पन्न हुई थी।
wirrbel

35
यह 100% है, JSON के मनमाने ढंग से पूरी तरह से वैध और मानक फ्लोटिंग-पॉइंट नंबर राज्य NaN, Infinity और -Infinity के लिए बिल्कुल गलत है। अनिवार्य रूप से, JSON ने IEEE फ्लोट मानों के एक अनियंत्रित उपसमूह का समर्थन करने का फैसला किया, अनजाने में तीन विशिष्ट मूल्यों को छोड़ दिया क्योंकि वे कठिन या कुछ और हैं। संख्या-क्षमता भी एक बहाना नहीं है, क्योंकि इस तरह की संख्याओं को शाब्दिक 1/0, -1/0 और 0/0 के रूप में एन्कोड किया जा सकता था। वे "/ 0" के साथ जोड़े गए मान्य नंबर होंगे, जो न केवल पता लगाने के लिए सरल है, बल्कि एक ही समय में ईएस के रूप में मूल्यांकन योग्य है। कोई बहाना नहीं।
त्रिवेंको

56

मूल प्रश्न पर: मैं उपयोगकर्ता "cbare" से सहमत हूं कि यह JSON में एक दुर्भाग्यपूर्ण चूक है। IEEE754 इन्हें फ्लोटिंग पॉइंट नंबर के तीन विशेष मानों के रूप में परिभाषित करता है। इसलिए JSON IEEE754 फ़्लोटिंग पॉइंट नंबरों का पूरी तरह से प्रतिनिधित्व नहीं कर सकता है। यह वास्तव में और भी बुरा है, क्योंकि JSON के रूप में ECMA262 5.1 में परिभाषित किया गया है, यह भी परिभाषित नहीं करता है कि इसकी संख्या IEEE754 पर आधारित है या नहीं। चूंकि ECMA262 में स्ट्रिंग () फ़ंक्शन के लिए वर्णित डिज़ाइन प्रवाह तीन विशेष IEEE मूल्यों का उल्लेख करता है, इसलिए किसी को संदेह हो सकता है कि IEEE754 फ़्लोटिंग पॉइंट नंबरों का समर्थन करने का इरादा वास्तव में था।

एक अन्य डेटा बिंदु के रूप में, प्रश्न से असंबंधित: XML डेटाटाइप्स xs: फ्लोट और एक्सएस: डबल करते हैं कि वे IEEE754 फ्लोटिंग पॉइंट संख्या पर आधारित हैं, और वे इन तीन विशेष मूल्यों के प्रतिनिधित्व का समर्थन करते हैं (देखें X3C XSD 1.0 पार्ट 2 देखें) , जानकारी का प्रकार)।


5
मैं मानता हूं कि यह सब दुर्भाग्यपूर्ण है। लेकिन शायद यह एक अच्छी बात है कि JSON नंबर सटीक फ्लोटिंग पॉइंट फॉर्मेट को निर्दिष्ट नहीं करता है। यहां तक ​​कि IEEE754 कई स्वरूपों को निर्दिष्ट करता है - अलग-अलग आकार, और दशमलव और बाइनरी एक्सपोर्टर के बीच अंतर। JSON दशमलव के लिए विशेष रूप से अनुकूल है, इसलिए यह एक दया होगी यदि कुछ मानक इसे बाइनरी में पिन करने के लिए थे।
एड्रियन रत्नापाला

5
@AdrianRatnapala +1 वास्तव में: JSON की संख्या में संभावित रूप से अनंत परिशुद्धता होती है, इसलिए IEEE विनिर्देशों की तुलना में बहुत बेहतर हैं, क्योंकि उनकी कोई आकार सीमा नहीं है, कोई सटीक सीमा नहीं है, और कोई राउंडिंग प्रभाव नहीं है (यदि धारावाहिक इसे संभाल सकते हैं)।
अरनौद बुचेज़

2
@ArnaudBouchez। उस ने कहा, JSON को अभी भी NaN और + -Infinity का प्रतिनिधित्व करने वाले तार का समर्थन करना चाहिए। भले ही JSON को किसी IEEE प्रारूप में पिन नहीं किया जाना चाहिए, लेकिन संख्या प्रारूप को परिभाषित करने वाले लोगों को कम से कम विकिपीडिया पृष्ठ IEEE754 को देखना चाहिए और सोचने के लिए थोड़ी देर रुकना चाहिए।
एड्रियन रत्नापला


यह दुर्भाग्यपूर्ण नहीं है। @CervEd द्वारा उत्तर देखें। यह IEE754 से बंधा नहीं है जो एक अच्छी बात है (भले ही अधिकांश प्रोग्रामिंग भाषा IEEE754 का उपयोग करें और इस प्रकार NaN के मामले में अतिरिक्त प्रसंस्करण की आवश्यकता होती है)।
लुडोविक क्यूट

16

क्या आप अशक्त ऑब्जेक्ट पैटर्न को अनुकूलित कर सकते हैं, और आपके 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 */}

मुझे पता है कि जावा में आप इस तरह की चीज़ को लागू करने के लिए क्रमबद्ध तरीकों को पार कर सकते हैं। निश्चित नहीं है कि आपका क्रमांकन कहाँ से हो रहा है, इसलिए मैं यह नहीं बता सकता कि इसे क्रमांकन विधियों में कैसे लागू किया जाए।


1
हम्म् ... यह एक वर्कअराउंड का जवाब है; मैं वास्तव में वर्कअराउंड के लिए नहीं कह रहा था, बल्कि इसके लिए कि इन मूल्यों को बाहर क्यों रखा गया था। लेकिन वैसे भी +1।
जेसन एस

2
@Zoidberg: undefinedएक कीवर्ड नहीं है, यह वैश्विक वस्तु पर एक संपत्ति है
olliej

2
@Zoidberg: अपरिभाषित वैश्विक वस्तु पर एक संपत्ति है - यह एक कीवर्ड नहीं है, इसलिए "undefined" in thisवैश्विक दायरे में सच है। इसका मतलब यह भी है कि आप ( undefined = 42और if (myVar == undefined)अनिवार्य रूप से) कर सकते हैं myVar == 42। यह एक्सेमस्क्रिप्ट nee जावास्क्रिप्ट के शुरुआती दिनों में वापस आ जाता है जहां undefinedडिफ़ॉल्ट रूप से मौजूद नहीं था, इसलिए लोगों ने सिर्फ var undefinedवैश्विक दायरे में किया। नतीजतन undefined, मौजूदा साइटों को तोड़े बिना एक कीवर्ड नहीं बनाया जा सकता है, और इसलिए हमें अनिर्दिष्ट होने के लिए हर समय एक सामान्य संपत्ति होने के लिए बर्बाद किया गया था।
इलियज

2
@olliej: मुझे नहीं पता कि आप क्यों सोचते हैं कि अपरिभाषित वैश्विक वस्तु पर एक संपत्ति है। डिफ़ॉल्ट रूप से अपरिभाषित का लुकअप अपरिभाषित का अंतर्निहित मूल्य है। यदि आप इसे "अपरिभाषित = 42" के साथ ओवरराइड करते हैं तो जब आप अपरिभाषित को एक चर खोज के रूप में एक्सेस करते हैं, तो आपको ओवरराइड मूल्य मिलता है। लेकिन "zz = अपरिभाषित; अपरिभाषित = 42; x = {}; अपरिभाषित पुराना = '+ (xa === zz) +', अपरिभाषित नया = '+ (xa = अपरिभाषित)" करने का प्रयास करें। आप कभी भी अशक्त, अपरिभाषित, NaN, या अनंत के आंतरिक मूल्यों को फिर से परिभाषित नहीं कर सकते, भले ही आप उनके प्रतीक लुक को ओवरराइड कर सकें।
जेसन एस

2
@ जेसन undefinedएक वैश्विक संपत्ति है क्योंकि यह इस प्रकार निर्दिष्ट है। ECMAScript-262 3rd एड के 15.1.1.3 से परामर्श करें।
kangax

11

स्ट्रिंग्स "इन्फिनिटी", "-इनफिनिटी", और "एनएएन" सभी जेएस में अपेक्षित मूल्यों के लिए जोर देते हैं। इसलिए मैं 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" है, आदि जिस तरह से आप रूपांतरण करते हैं वह कोड इंजेक्शन के लिए प्रवण होता है।
मार्को सुल्ला

3
JSON मूल्यों को अंकगणितीय अभिव्यक्ति नहीं किया जा सकता है ... भाषा को शाब्दिक वाक्य रचना से अलग मानक बनाने का लक्ष्य कोड के रूप में किसी को भी निष्पादित किए बिना JSON को पुन: प्रयोग करने योग्य बनाना है। सुनिश्चित नहीं हैं कि हम कीवर्ड मानों की तरह क्यों NaNऔर नहीं Infinityजोड़ सकते हैं trueऔर false, हालांकि।
मार्क रीड

इसे और अधिक स्पष्ट करने के लिए, हम उपयोग कर सकते हैं Number("Infinity"), Number("-Infinity")औरNumber("NaN")
HKTonyLee

यह जादू की तरह काम है। जावास्क्रिप्ट में JSON.parse("{ \"value\" : -1e99999 }")आसानी से लौटते हैं { value:-Infinity }। केवल यह केवल कस्टम संख्या प्रकार के साथ संगत नहीं है जो इससे बड़ा हो सकता है
थैना

7

यदि आपके पास क्रमांकन कोड तक पहुंच है तो आप 1.0e + 1024 के रूप में इन्फिनिटी का प्रतिनिधित्व कर सकते हैं। घातांक एक दोहरे में प्रतिनिधित्व करने के लिए बहुत बड़ा है और जब deserialized यह इन्फिनिटी के रूप में प्रतिनिधित्व किया है। वेबकिट पर काम करता है, अन्य जसन पार्सर के बारे में अनिश्चित!


4
IEEE754 128 बिट फ्लोटिंग पॉइंट नंबरों का समर्थन करता है इसलिए 1.0e5000 बेहतर है
टन

2
टन: 128 बिट बाद में जोड़ा गया था। क्या होगा यदि वे 256 बिट जोड़ने का निर्णय लेते हैं? फिर आपको अधिक शून्य जोड़ना होगा, और मौजूदा कोड अलग तरह से व्यवहार करेगा। Infinityहमेशा रहेगा Infinity, तो उसका समर्थन क्यों नहीं?
उड़ान भेड़

1
चतुर विचार! मैं बस एक अलग प्रारूप पर स्विच करने या अपने पार्सर में बोझिल वर्कअराउंड कोड जोड़ने के बारे में था। हर मामले के लिए आदर्श नहीं है, लेकिन मेरे मामले में, जहां अनन्तता एक अभिसरण अनुक्रम के लिए एक अनुकूलित किनारे के मामले के रूप में कार्य करता है, यह सिर्फ सही है और यहां तक ​​कि अगर बड़ी सटीकता का परिचय होगा तो यह अभी भी ज्यादातर सही होगा। धन्यवाद!
या शरिर

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'। कोई बहाना नहीं।
ट्राइंको


1

वर्तमान IEEE Std 754-2008 में दो अलग-अलग 64-बिट फ़्लोटिंग-पॉइंट अभ्यावेदन के लिए परिभाषाएँ शामिल हैं: एक दशमलव 64-बिट फ़्लोटिंग-पॉइंट प्रकार और एक बाइनरी 64-बिट फ़्लोटिंग-पॉइंट प्रकार।

स्ट्रिंग गोलाई के बाद .99999990000000006के रूप में ही है .9999999आईईईई बाइनरी 64-बिट प्रतिनिधित्व में, लेकिन यह है नहीं के रूप में ही .9999999आईईईई दशमलव 64-बिट प्रतिनिधित्व में। 64-बिट IEEE दशमलव फ़्लोटिंग-पॉइंट .99999990000000006राउंड के मान के लिए .9999999000000001जो दशमलव .9999999मान के समान नहीं है ।

चूँकि JSON केवल दशमलव अंकों के संख्यात्मक तार के रूप में संख्यात्मक मानों का व्यवहार करता है, इसलिए ऐसी प्रणाली के लिए कोई रास्ता नहीं है जो IEEE बाइनरी और दशमलव फ़्लोटिंग-पॉइंट निरूपण (जैसे IBM Power) दोनों का समर्थन करता है, यह निर्धारित करने के लिए कि दो संभावित IEEE संख्यात्मक फ़्लोट-पॉइंट मानों में से कौन सा है? इरादा है।


प्रश्न से इसका क्या लेना-देना है? (जो इन्फिनिटी और NaN के बारे में है)
ब्रायन

1

{"की" जैसे मामलों के लिए संभावित कार्य-आसपास: इन्फिनिटी}:

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;
   });

सामान्य विचार एक स्ट्रिंग के साथ अवैध मूल्यों की घटनाओं को प्रतिस्थापित करना है जिसे हम पहचानेंगे जब पार्सिंग करेंगे और इसे उपयुक्त जावास्क्रिप्ट प्रतिनिधित्व के साथ वापस बदल देंगे।


मुझे नहीं पता कि इस समाधान में गिरावट क्यों आई क्योंकि स्पष्ट रूप से, यदि आप एक ऐसी स्थिति का सामना करते हैं जहां आपके JSON स्ट्रिंग में Infinity या IsNaN मान शामिल हैं, तो जब आप इसे पार्स करने का प्रयास करेंगे तो यह विफल हो जाएगा। इस तकनीक का उपयोग करते हुए, आप पहले IsNaN या Infinity की घटनाओं को किसी अन्य चीज़ से प्रतिस्थापित करते हैं (उन्हें किसी भी वैध स्ट्रिंग से अलग करने के लिए जो उन शर्तों को शामिल कर सकते हैं), और उचित, वैध एकीकृत मानों को वापस करने के लिए JSON.parse (स्ट्रिंग, कॉलबैक) का उपयोग करें। मैं इसे उत्पादन कोड में उपयोग कर रहा हूं और कभी भी कोई समस्या नहीं थी।
शोमल

स्ट्रिंग्स के अंदर इन्फिनिटी को गड़बड़ नहीं करेगा? कई usecases के लिए यह मान लेना सुरक्षित है कि यह कोई मुद्दा नहीं है, लेकिन समाधान पूरी तरह से मजबूत नहीं है।
olejorgenb

1

इसका कारण मानक ECMA-404 में JSON डेटा इंटरचेंज सिंटैक्स, प्रथम संस्करण में पृष्ठ ii पर बताया गया है

JSON संख्याओं के बारे में अज्ञेयवादी है। किसी भी प्रोग्रामिंग भाषा में, कई प्रकार की विभिन्न प्रकार की क्षमताएं और पूरक, फिक्स्ड या फ्लोटिंग, बाइनरी या दशमलव हो सकते हैं। जो विभिन्न प्रोग्रामिंग भाषाओं के बीच इंटरचेंज को कठिन बना सकता है। JSON इसके बजाय केवल उन संख्याओं का प्रतिनिधित्व करता है जो मानव उपयोग करते हैं: अंकों का एक क्रम। सभी प्रोग्रामिंग भाषाएं यह जानती हैं कि आंतरिक अनुक्रमों पर असहमत होने पर भी वे अंकों के अनुक्रम की समझ कैसे बनाते हैं। यह इंटरचेंज की अनुमति देने के लिए पर्याप्त है।

इसका कारण यह नहीं है, जैसा कि NaNऔर Infinityईसीएमए लिपि के प्रतिनिधित्व के कारण, कई लोगों ने दावा किया है । सादगी JSON का एक मुख्य डिजाइन सिद्धांत है।

क्योंकि यह इतना सरल है, यह उम्मीद नहीं है कि JSON व्याकरण कभी भी बदल जाएगा। यह JSON देता है, एक मूलभूत संकेतन के रूप में, जबरदस्त स्थिरता


-3

अगर मेरी तरह आपके पास सीरियलाइज़ेशन कोड पर कोई नियंत्रण नहीं है, तो आप NaN मानों को एक हैक के एक बिट के रूप में नल या किसी अन्य मूल्य के साथ बदलकर सौदा कर सकते हैं:

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

संक्षेप में, .fail तब मिलेगा जब मूल जन्स पार्सर एक अमान्य टोकन का पता लगाता है। फिर अमान्य टोकन को बदलने के लिए एक स्ट्रिंग प्रतिस्थापित किया जाता है। मेरे मामले में यह धारावाहिक के लिए NaN मूल्यों को वापस करने के लिए एक अपवाद है, इसलिए यह विधि सबसे अच्छा तरीका है। यदि परिणामों में सामान्य रूप से अमान्य टोकन होते हैं, तो आप $ .get का उपयोग न करना बेहतर होगा, लेकिन इसके बजाय मैन्युअल रूप से JSON परिणाम प्राप्त करें और हमेशा स्ट्रिंग प्रतिस्थापन चलाएँ।


21
चतुर, लेकिन पूरी तरह से मूर्ख नहीं। इसके साथ कोशिश करें{ "tune": "NaNaNaNaNaNaNaNa BATMAN", "score": NaN }
JJJ

1
और आपको jQuery का उपयोग करना चाहिए। मेरे पास $ .get () नहीं है।
जेसन एस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.