ทำไม parseInt (8,3) == NaN และ parseInt (16,3) == 1


191

ฉันกำลังอ่านสิ่งนี้แต่ฉันสับสนกับสิ่งที่เขียนในparseInt ด้วยบทโต้แย้ง radix

สารบัญผลลัพธ์ (_, 3)

ทำไมมันจึงเป็นที่parseInt(8, 3)NaNและparseInt(16, 3)1?

AFAIK 8 และ 16 ไม่ใช่ตัวเลขเบส -3 ดังนั้นparseInt(16, 3)ควรส่งคืนNaNด้วย

เลขฐานสิบสามแรกแรกตามธรรมชาติ


4
อีกปัญหาหนึ่งที่จะได้รับการแก้ไขโดยการพิมพ์แบบสแตติก (หรืออย่างน้อยก็ไม่ต้องแปลงจำนวนเต็มเป็นสตริงโดยปริยาย): P
Navin

4
@Navin สิ่งนี้ไม่มีส่วนเกี่ยวข้องกับการพิมพ์แบบคงที่และแบบไดนามิก (ตามที่คุณจดบันทึกตัวเอง) ปัญหาที่นี่อ่อนแอเมื่อเทียบกับการพิมพ์ที่แข็งแกร่ง
Sven Marnach

12
เมื่อฉันเห็นชื่อของคำถามนี้ฉันคิดกับตัวเอง "อาจเป็นเพราะ loljavascript" เห็นคำตอบที่ฉันตัดสินสัญชาตญาณของฉันถูกต้องโดยทั่วไป
Ben Millwood

คำตอบ:


373

นี่คือสิ่งที่ผู้คนเดินทางตลอดเวลาแม้ว่าพวกเขาจะรู้ :-) คุณเห็นสิ่งนี้ด้วยเหตุผลเดียวกันparseInt("1abc")ส่งคืน 1: parseIntหยุดที่อักขระที่ไม่ถูกต้องตัวแรกและส่งคืนสิ่งที่มีอยู่ ณ จุดนั้น หากไม่มีอักขระที่ถูกต้องในการวิเคราะห์NaNคำ

parseInt(8, 3)หมายถึง "แยกวิเคราะห์"8"ในฐาน 3" (โปรดทราบว่าจะแปลงตัวเลข8เป็นสตริง; รายละเอียดในข้อมูลจำเพาะ ) แต่ในฐานที่ 3 ตัวเลขหลักเดียวเป็นเพียง0, และ1 2มันก็เหมือนกับการขอให้มันแยกเป็น"9"แปด เนื่องจากมีไม่มีNaNอักขระที่ถูกต้องที่คุณได้

parseInt(16, 3)กำลังขอให้แยกวิเคราะห์"16"ในฐาน 3 เนื่องจากสามารถแยกวิเคราะห์1แล้วทำและหยุดที่6เนื่องจากไม่สามารถแยกวิเคราะห์ได้ ดังนั้นมันจึงกลับ1มา


เนื่องจากคำถามนี้ได้รับความสนใจเป็นอย่างมากและอาจอยู่ในอันดับที่สูงในผลการค้นหานี่คือบทสรุปของตัวเลือกสำหรับการแปลงสตริงเป็นตัวเลขใน JavaScript โดยใช้ idiosyncracies และแอปพลิเคชันต่าง ๆ (ยกจากคำตอบอื่นของฉันที่นี่)

  • parseInt(str[, radix])- แปลงจุดเริ่มต้นของสตริงให้มากที่สุดเท่าที่จะเป็นจำนวนเต็ม (จำนวนเต็ม) โดยไม่สนใจอักขระพิเศษในตอนท้าย ดังนั้นparseInt("10x")คือ10; xจะถูกละเว้น รองรับอาร์กิวเมนต์ radix (ฐานตัวเลข) ที่เป็นตัวเลือกดังนั้นparseInt("15", 16)คือ21( เป็น15ฐานสิบหก) หากไม่มี radix ให้ถือว่าทศนิยมยกเว้นว่าสตริงนั้นขึ้นต้นด้วย0x(หรือ0X) ในกรณีนี้มันจะข้ามมันและถือว่าเป็น hex (เบราว์เซอร์บางตัวใช้เพื่อจัดการกับสตริงที่ขึ้นต้นด้วย0octal พฤติกรรมดังกล่าวไม่เคยถูกระบุและไม่ได้รับอนุญาตเป็นการเฉพาะในข้อกำหนด ES5)ส่งคืนNaNหากไม่พบตัวเลขที่สามารถแยกวิเคราะห์ได้

  • parseFloat(str)- ชอบparseIntแต่ทำตัวเลขทศนิยมและสนับสนุนทศนิยมเท่านั้น อักขระพิเศษอีกครั้งบนสตริงจะถูกละเว้นดังนั้นparseFloat("10.5x")คือ10.5( xถูกละเว้น) รองรับทศนิยมเท่านั้นคือparseFloat("0x15")คือ0(เนื่องจากการแยกวิเคราะห์สิ้นสุดที่x) ส่งคืนNaNหากไม่พบตัวเลขที่สามารถแยกวิเคราะห์ได้

  • Unary +เช่น+str- (เช่นการแปลงโดยนัย)แปลงสตริงทั้งหมดเป็นตัวเลขโดยใช้ทศนิยมและสัญลักษณ์มาตรฐานของ JavaScript (เฉพาะตัวเลขและจุดทศนิยม = ทศนิยม; 0xคำนำหน้า = hex; 0oคำนำหน้า = ฐานแปด [ES2015 +] การใช้งานบางอย่างขยาย เพื่อรักษาผู้นำที่0เป็นฐานแปด แต่ไม่อยู่ในโหมดเข้มงวด) +"10x"เป็นNaNเพราะxจะไม่ละเว้น +"10"คือ10, +"10.5"คือ10.5, +"0x15"คือ21, +"0o10"เป็น8[ES2015 +] มี gotcha: +""คือ0ไม่ใช่NaNอย่างที่คุณคาดหวัง

  • Number(str)- เหมือนกับการแปลงโดยนัย (เช่นเช่นเดียวกับที่กล่าว+ไว้ข้างต้น) แต่ช้ากว่าในการใช้งานบางอย่าง (ไม่ใช่ว่ามันเป็นเรื่องสำคัญ)


8
ดังนั้นparseIntใช้ครั้งแรกtoStringกับอาร์กิวเมนต์แรกหรือไม่ นั่นจะทำให้รู้สึก
evolutionxbox

16
@evolutionxbox: ใช่มันเป็นขั้นตอนแรกของparseIntอัลกอริทึม: ecma-international.org/ecma-262/7.0/…
TJ Crowder

5
ฉันคิดว่า123e-2ให้1ตั้งแต่มันกลายเป็น1.23ครั้งแรกแล้วแยกหยุดที่จุดทศนิยม?
ilkkachu

6
"นี่คือสิ่งที่ผู้คนเดินทางตลอดเวลาแม้ว่าพวกเขาจะรู้เรื่องนี้" -> ฉันเป็นคนเดียวที่คิดว่านี่น่าจะเป็นแมลงหรือไม่? ยกตัวอย่างเช่นใน Java จะให้NumberFormatExceptionแต่ละครั้ง
Wim Deblauwe

4
@SvenMarnach: นั่นเป็นส่วนหนึ่งของparseInt(บีบบังคับอาร์กิวเมนต์แรกสตริง) ทำให้รู้สึก วัตถุประสงค์ของการparseIntคือการแยกสตริงเป็นจำนวนเต็ม ดังนั้นถ้าคุณให้มันเป็นสิ่งที่ไม่ใช่สตริงการได้รับการแทนสตริงเพื่อเริ่มต้นด้วยความสมเหตุสมผล มันจะทำอย่างไรหลังจากนั้นเป็นเรื่อง 'nother ทั้งหมด ...
TJ Crowder

54

ด้วยเหตุผลเดียวกันนั้นเอง

>> parseInt('1foobar',3)
<- 1

ในเอกสาร , parseIntใช้เวลาสตริง และ

หากสตริงไม่ใช่สตริงแสดงว่าสตริงนั้นถูกแปลงเป็นสตริง

ดังนั้น16, 8หรือ'1foobar'ถูกแปลงแรกที่จะสตริง

แล้วก็

หากparseIntพบอักขระที่ไม่ใช่ตัวเลขใน radix ที่ระบุไว้ระบบจะละเว้นอักขระนั้นและอักขระที่ประสบความสำเร็จทั้งหมด

หมายความว่ามันสามารถแปลงไปยังจุดที่สามารถทำได้ The 6, 8และfoobarถูกละเว้นและสิ่งที่ก่อนหน้านี้จะถูกแปลง หากไม่มีอะไรNaNจะถูกส่งกลับ


0
/***** Radix 3: Allowed numbers are [0,1,2] ********/
parseInt(4, 3); // NaN - We can't represent 4 using radix 3 [allowed - 0,1,2]

parseInt(3, 3); // NaN - We can't represent 3 using radix 3 [allowed - 0,1,2]

parseInt(2, 3); // 2   - yes we can !

parseInt(8, 3); // NaN - We can't represent 8 using radix 3 [allowed - 0,1,2]

parseInt(16, 3); // 1  
//'16' => '1' (6 ignored because it not in [0,1,2])    

/***** Radix 16: Allowed numbers/characters are [0-9,A-F] *****/ 
parseInt('FOX9', 16); // 15  
//'FOX9' => 'F' => 15 (decimal value of 'F')
// all characters from 'O' to end will be ignored once it encounters the out of range'O'
// 'O' it is NOT in [0-9,A-F]

ตัวอย่างเพิ่มเติม:

parseInt('45', 13); // 57
// both 4 and 5 are allowed in Radix is 13 [0-9,A-C]

parseInt('1011', 2); // 11 (decimal NOT binary)

parseInt(7,8); // 7
// '7' => 7 in radix 8 [0 - 7]

parseInt(786,8); // 7 
// '78' => '7' => 7 (8 & next any numbers are ignored bcos 8 is NOT in [0-7])

parseInt(76,8); // 62 
// Both 7 & 6 are allowed '76' base 8 decimal conversion is 62 base 10 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.