2014-09-24 22 views
27

आज मैं जावास्क्रिप्ट में एक अजीब (मेरी राय में) मामले पर ठोकर खाई। मैंने 16 के आधार के साथ parseInt फ़ंक्शन में एक गैर-हेक्साडेसिमल स्ट्रिंग पास की और ... मुझे परिणाम मिला। मैं उम्मीद करता हूं कि फ़ंक्शन किसी प्रकार का अपवाद फेंक देगा या कम से कम नाएन वापस लौटाएगा, लेकिन यह इसे पार्स करने में सफल रहा और एक int वापस कर दिया।parseInt क्यों ('dsff66', 16) 13 लौटाता है?

मेरे फोन था:

var parsed = parseInt('dsff66', 16); // note the 's' in the first argument 
 
document.write(parsed);

और परिणाम था: 13

मैंने देखा कि यह पहले वर्ण के साथ पार्सिंग "रोकता है" जो दूसरे तर्क में निर्दिष्ट संख्या प्रणाली से संबंधित नहीं है, इसलिए parseInt('fg',16) पर कॉल करने के परिणामस्वरूप मुझे 15 मिल जाएगा।

मेरी राय में, इसे NaN वापस करना चाहिए। क्या कोई मुझे समझा सकता है कि ऐसा क्यों नहीं करता? कोई भी इस फ़ंक्शन को इस तरह व्यवहार करने के लिए क्यों चाहेगा (एक पूर्णांक लौटाएं भले ही यह पारित स्ट्रिंग का सटीक प्रतिनिधित्व न हो)?

+8

ध्यान दें कि आप 'parseInt की तरह कुछ करते हैं (" 2foo ", 10) 'आपको '2' मिलता है। यह उम्मीद के रूप में है। यह पहले गैर-अंकीय चरित्र –

+35

तक पार्स करता है * मेरी राय में, इसे NaN वापस करना चाहिए। क्या कोई मुझे बता सकता है कि यह क्यों नहीं करता है? * क्योंकि कल्पना कहती है कि यह नहीं होना चाहिए। और दुर्भाग्यवश, मेरी राय या तुम्हारी कल्पना से कोई फर्क नहीं पड़ता। –

+14

'यदि parseInt एक वर्ण से मुठभेड़ नहीं करता है जो निर्दिष्ट रेडिक्स में कोई अंक नहीं है, तो यह इसे और सभी सफल वर्णों को अनदेखा करता है और उस बिंदु तक पार्स किए गए पूर्णांक मान देता है। स्रोत: https://developer.mozilla.org/en- यूएस/डॉक्स/वेब/जावास्क्रिप्ट/संदर्भ/ग्लोबल_ऑब्जेक्ट्स/पैरासेन्ट –

उत्तर

22

क्यों किसी को भी इस समारोह (इस तरह व्यवहार करने के लिए एक पूर्णांक लौट चाहेगा तो भी यह सटीक नहीं है पारित स्ट्रिंग का प्रतिनिधित्व)?

क्योंकि समय के सबसे अधिक (अब तक) आप आधार 10 की संख्या के साथ काम कर रहे हैं, और उस मामले में जे एस सिर्फ डाली कर सकते हैं - एक नंबर करने के स्ट्रिंग - पार्स नहीं। (संपादित करें: स्पष्ट रूप से केवल बेस -10 नहीं; नीचे अपडेट देखें।)

चूंकि जेएस गतिशील रूप से टाइप किया गया है, इसलिए कुछ तार आपके हिस्से पर किसी भी काम के बिना संख्याओं के ठीक ठीक काम करते हैं। उदाहरण के लिए:

"21"/3; // => 7 
"12.4"/4; // => 3.1 

वहाँ parseInt के लिए कोई ज़रूरत नहीं है, क्योंकि "21" और "12.4" अनिवार्य रूप से संख्या पहले से ही कर रहे हैं। यदि, हालांकि स्ट्रिंग "12.4xyz" थी तो आपको NaN को विभाजित करते समय वास्तव में प्राप्त होगा, क्योंकि यह निश्चित रूप से एक संख्या नहीं है और इसे स्पष्ट रूप से कास्ट या कॉरसेड नहीं किया जा सकता है।

आप Number(someString) के साथ एक स्ट्रिंग को स्पष्ट रूप से "कास्ट" भी कर सकते हैं। हालांकि यह केवल आधार 10, का समर्थन करता है, यह वास्तव में अमान्य तारों के लिए NaN लौटाएगा।

इसलिए क्योंकि जेएस के पास पहले से ही निहित और स्पष्ट प्रकार का कास्टिंग/रूपांतरण/जबरन है, parseInt की भूमिका अभी तक एक और प्रकार का कास्टिंग फ़ंक्शन नहीं है।

parseInt की भूमिका इसके बजाय, पार्सिंग फ़ंक्शन के बजाय है। एक ऐसा फ़ंक्शन जो इसके इनपुट को समझने के लिए सबसे अच्छा प्रयास करता है, जो वह कर सकता है उसे लौटता है। यह तब होता है जब आपके पास स्ट्रिंग है नहीं डाला जा सकता है क्योंकि यह बिल्कुल पूरी तरह से संख्यात्मक नहीं है। (और, जेएस के मूल वाक्यविन्यास की तरह, यह सी की याद दिलाता है, क्योंकि एपिलर्स के उत्तर अच्छी तरह से समझाया गया है।)

और चूंकि यह एक पार्सर है, एक कास्टिंग फ़ंक्शन नहीं है, इसलिए इसे 10 से अधिक अन्य अड्डों को संभालने में सक्षम होने की अतिरिक्त सुविधा मिल गई है। ।

अब, तुम क्यों नहीं है एक सख्त कास्टिंग समारोह है कि गैर आधार -10 संख्या संभालती पूछ सकते हैं, और शिकायत की तरह आप चाहते हैं, लेकिन ... अरे, वहाँ बस नहीं है। जेएस के डिजाइनरों ने अभी फैसला किया है कि parseInt पर्याप्त होगा, क्योंकि, फिर से 0x63 प्रतिशत, आप आधार 10 से निपट रहे हैं।

var hexString = "dsff66"; 
var number = eval("0x" + hexString); // attempt to interpret as a hexadecimal literal 

which'll फेंक एक SyntaxError क्योंकि 0xdsff66 मान्य हेक्स शाब्दिक नहीं है:

निकटतम आप "कास्टिंग" करने के लिए प्राप्त कर सकते हैं शायद कुछ बुरी hacky की तरह है।

अद्यतन: Lekensteyn टिप्पणी में बताते हैं के रूप में, जे एस प्रकट होता है ठीक से 0x -prefixed हेक्साडेसिमल तार भी कास्ट करने के लिए। मैं यह नहीं पता था, लेकिन वास्तव में यह काम करने के लिए लगता है:

1 * "0xd0ff66"; // => 13696870 
1 * "0xdsff66"; // => NaN 

जो इसे एक संख्या के लिए एक हेक्स स्ट्रिंग कास्ट करने के लिए सबसे आसान तरीका है - और NaN प्राप्त करता है, तो यह ठीक से प्रदर्शित नहीं किया जा सकता है।

वही व्यवहार Number() पर लागू होता है, उदा Number("0xd0ff66") एक पूर्णांक देता है, और Number("0xdsff66") रिटर्न NaN

(/अद्यतन)

वैकल्पिक रूप से, आप स्ट्रिंग पहले उनकी जांच और NaN वापसी यदि आवश्यक हो तो कर सकते हैं:

function hexToNumber(string) { 
    if(!/^(0x)?[0-9a-f]+$/i.test(string)) return Number.NaN; 
    return parseInt(string, 16); 
} 
+5

ईडब्ल्यू, 'eval'। एक संख्या में स्ट्रिंग को "कास्टिंग" करके, आप एक समान प्रभाव डाल सकते हैं। '1 *" 0xdsff66 "' कम से कम फ़ायरफ़ॉक्स में 'NaN' देता है। यह जांचना कि क्या यह spec की पुष्टि करता है पाठक के लिए एक अभ्यास है। – Lekensteyn

+0

@Lekensteyn हाँ, ईडब्ल्यू। मैंने कहा कि यह भयानक था :) लेकिन दिलचस्प है कि '0x'-prefixed स्ट्रिंग भी डाली जाती है! उसे नहीं पता था - क्रोम में भी ठीक काम करता है। – Flambino

+0

अच्छा, यह एक अच्छा स्पष्टीकरण है :) आप दोनों को धन्यवाद। –

43

parseInt इनपुट पढ़ता है जब तक यह कोई अमान्य वर्ण का सामना करना पड़ता है, और फिर जो कुछ भी मान्य इनपुट यह है कि अमान्य वर्ण से पहले पढ़ उपयोग करता है। पर विचार करें:

parseInt("17days", 10); 

इस इनपुट 17 का उपयोग करें और अवैध d के बाद सब कुछ छोड़ देगा।

से ECMAScript specification:

हैं [इनपुट स्ट्रिंग] एस किसी भी चरित्र है कि एक मूलांक-आर अंकों नहीं करतीं, तो जेड [स्ट्रिंग पूर्णांक-ified होने के लिए] जाने एस के सबस्ट्रिंग हो पहले ऐसे चरित्र से पहले सभी पात्रों से मिलकर; अन्यथा, जेड एस

हो अपने उदाहरण में जाने, s गलत आधार -16 चरित्र है, इसलिए parseInt केवल प्रमुख d उपयोग करता है। के लिए

के रूप में क्यों इस व्यवहार शामिल किया गया था: वहाँ कोई रास्ता नहीं है निश्चित रूप से जानना है, लेकिन यह काफी संभावना सी मानक पुस्तकालय से (लंबी करने के लिए स्ट्रिंग) strtol के व्यवहार पुन: पेश करने का एक प्रयास है। strtol(3) man page से:

... स्ट्रिंग स्पष्ट तरीके से एक लंबे पूर्णांक मूल्य में बदल जाती है, पहला वर्ण जो दिया आधार में एक वैध अंकों नहीं है पर रोक।

इस संबंध आगे तथ्य यह है कि parseInt और strtol दोनों प्रमुख खाली स्थान के अनदेखी करने के लिए निर्दिष्ट कर रहे हैं द्वारा (कुछ हद तक) समर्थित है, और वे दोनों हेक्साडेसिमल मूल्यों के लिए एक प्रमुख 0x स्वीकार कर सकते हैं।

+0

+1। – Robert

6

For radices above 10, the letters of the alphabet indicate numerals greater than 9. For example, for hexadecimal numbers (base 16), A through F are used.

अपने स्ट्रिंग dsff66 में, d हेक्साडेसिमल चरित्र (भले ही स्ट्रिंग गैर हेक्स है) जो मूलांक प्रकार फिट बैठता है और संख्या 13 के बराबर है है।इसके बाद यह पार्सिंग बंद कर देता है क्योंकि अगला चरित्र हेक्साडेसिमल नहीं है इसलिए परिणाम।

12

इस विशेष मामले parseInt() में "F"hexadecimal के रूप में "A" से पत्र की व्याख्या और दशमलव संख्या के लिए उन पार्स। इसका मतलब है d13 लौटाएगा।

क्या parseInt()

  • parseInt("string", radix) नंबर करने के लिए (यह मूलांक पर निर्भर करते हैं) हेक्साडेसिमल के रूप में स्ट्रिंग में संख्या और अक्षरों की व्याख्या करता है।

  • parseInt() स्ट्रिंग की शुरुआत से हेक्साडेसिमल के रूप में केवल पार्स संख्या या अक्षर हेक्साडेसिमल के रूप में अमान्य वर्ण तक।

  • तो parseInt() स्ट्रिंग parseInt() की शुरुआत में किसी भी संख्या या हेक्साडेसिमल के रूप में पत्र वापस आ जाएगी NaN नहीं मिल रहा।

  • यदि रेडिक्स परिभाषित नहीं किया गया है, तो रेडिक्स 10 है।

  • यदि स्ट्रिंग "0x" से शुरू होती है, तो रेडिक्स 16 है।

  • यदि रेडिक्स 0 परिभाषित किया गया है, तो रेडिक्स 10 है।

  • यदि रेडिक्स 1 है, parseInt() वापस नाएन।

  • मूलांक 2 है, तो parseInt() केवल "0" और "1" पार्स।

  • मूलांक 3, parseInt है() केवल पार्स "0", "1", और "2"। और इसी तरह।

  • parseInt() पार्स "0"0 को अगर कोई नंबर परिणाम के रूप में यह इस प्रकार और 0 को दूर करता है, तो वहाँ संख्या यह इस प्रकार है। जैसे "0" वापसी 0 और "01" वापसी 1.

  • मूलांक 11 है, तो parseInt() केवल पार्स स्ट्रिंग कि "0" से "9" और/या पत्र "A" को संख्या के साथ शुरू होता है।

  • मूलांक 12 है, तो parseInt केवल स्ट्रिंग कि "0" से "9" और/या पत्र "A" और "B", और इतने पर करने के लिए संख्या के साथ शुरू होता पार्स।

  • अधिकतम मूलांक 36, यह स्ट्रिंग है "0" से "Z" को "A" से "9" और/या पत्र के लिए संख्या के साथ शुरू होता पार्स जाएगा।

  • यदि वर्ण एक से अधिक हेक्साडेसिमल के रूप में व्याख्या करते हैं, तो प्रत्येक पात्र के पास अलग-अलग मूल्य होंगे, हालांकि ये वर्ण एक ही वर्ण हैं। जैसे parseInt("AA", 11) पहले "A" के दूसरे "A" के साथ अलग-अलग मूल्य है।

  • विभिन्न रेडिक्स अलग-अलग नंबर लौटाएंगे हालांकि स्ट्रिंग एक ही स्ट्रिंग है।

कार्य करते हुए देखें

document.body.innerHTML = "<b>What parseInt() does</b><br>" + 
 
          "parseInt('9') = " + parseInt('9') + "<br>" + 
 
          "parseInt('0129ABZ', 0) = " + parseInt('0129ABZ', 0) + "<br>" + 
 
          "parseInt('0', 1) = " + parseInt('0', 1) + "<br>" + 
 
          "parseInt('0', 2) = " + parseInt('0', 2) + "<br>" + 
 
          "parseInt('10', 2) = " + parseInt('10', 2) + "<br>" + 
 
          "parseInt('01', 2) = " + parseInt('01', 2) + "<br>" + 
 
          "parseInt('1', 2) = " + parseInt('1', 2) + "<br>" + 
 
          "parseInt('A', 10) = " + parseInt('A', 10) + "<br>" + 
 
          "parseInt('A', 11) = " + parseInt('A', 11) + "<br>" + 
 
          "parseInt('Z', 36) = " + parseInt('Z', 36) + "<br><br>" + 
 
          "<b>The value:</b><br>" + 
 
          "parseInt('A', 11) = " + parseInt('A', 11) + "<br>" + 
 
          "parseInt('A', 12) = " + parseInt('A', 12) + "<br>" + 
 
          "parseInt('A', 13) = " + parseInt('A', 13) + "<br>" + 
 
          "parseInt('AA', 11) = " + parseInt('AA', 11) + " = 100 + 20" + "<br>" + 
 
          "parseInt('AA', 12) = " + parseInt('AA', 12) + " = 100 + 30" + "<br>" + 
 
          "parseInt('AA', 13) = " + parseInt('AA', 13) + " = 100 + 40" + "<br>" + 
 
          "parseInt('AAA', 11) = " + parseInt('AAA', 11) + " = 1000 + 300 + 30" + "<br>" + 
 
          "parseInt('AAA', 12) = " + parseInt('AAA', 12) + " = 1000 + 500 + 70" + "<br>" + 
 
          "parseInt('AAA', 13) = " + parseInt('AAA', 13) + " = 1000 + 700 + 130" + "<br>" + 
 
          "parseInt('AAA', 14) = " + parseInt('AAA', 14) + " = 1000 + 900 + 210" + "<br>" + 
 
          "parseInt('AAA', 15) = " + parseInt('AAA', 15) + " = 1000 + 1100 + 310";

+1

'यदि रेडिक्स परिभाषित नहीं किया गया है, तो रेडिक्स 10. है - भले ही यह _generally_ true है, पुराने ब्राउज़र 8 के रेडिक्स में डिफ़ॉल्ट हो सकते हैं। देखें [MDN पर parseInt] (https://developer.mozilla.org/en- अमेरिका/docs/वेब/जावास्क्रिप्ट/संदर्भ/Global_Objects/parseInt)। –

संबंधित मुद्दे