Mengapa parseInt (8,3) == NaN dan parseInt (16,3) == 1?

191

Saya membaca ini tetapi saya bingung dengan apa yang ditulis di parseInt dengan bab argumen radix

tabel hasil parseInt (_, 3)

Mengapa begitu parseInt(8, 3)NaNdan parseInt(16, 3)1?

AFAIK 8 dan 16 bukan angka dasar-3, jadi parseInt(16, 3)harus kembali NaNjuga

sepuluh basa dasar-3 pertama

Devid Farinelli
sumber
4
Namun masalah lain yang akan diselesaikan dengan mengetik statis (atau setidaknya tidak secara implisit mengkonversi bilangan bulat ke string): P
Navin
4
@Navin Ini tidak ada hubungannya dengan pengetikan statis versus dinamis (seperti yang Anda perhatikan sendiri). Masalahnya di sini lemah dibandingkan dengan pengetikan yang kuat.
Sven Marnach
12
Ketika saya melihat judul pertanyaan ini, saya berpikir, "itu mungkin karena loljavascript". Melihat jawabannya saya menilai naluri saya pada dasarnya benar.
Ben Millwood

Jawaban:

373

Ini adalah sesuatu yang sering dilalui orang, bahkan ketika mereka mengetahuinya. :-) Anda melihat ini karena alasan yang sama parseInt("1abc")mengembalikan 1: parseIntberhenti pada karakter pertama yang tidak valid dan mengembalikan apa pun yang dimilikinya pada saat itu. Jika tidak ada karakter yang valid untuk diurai, ia kembali NaN.

parseInt(8, 3)berarti "parse "8"in base 3" (perhatikan bahwa ia mengonversi angka 8menjadi string; perincian dalam spesifikasi ). Tapi dalam basis 3, nomor satu digit hanya 0, 1, dan 2. Ini seperti memintanya untuk menguraikan "9"dalam oktal. Karena tidak ada karakter yang valid, Anda dapat NaN.

parseInt(16, 3)memintanya untuk menguraikan "16"dalam basis 3. Karena ia dapat menguraikan 1, itu, dan kemudian berhenti pada 6karena tidak dapat menguraikannya. Jadi ia kembali 1.


Karena pertanyaan ini mendapatkan banyak perhatian dan mungkin mendapat peringkat tinggi dalam hasil pencarian, inilah daftar opsi untuk mengubah string menjadi angka dalam JavaScript, dengan berbagai keanehan dan aplikasi mereka (diangkat dari jawaban saya yang lain di sini di SO):

  • parseInt(str[, radix])- Mengubah sebanyak mungkin bagian awal string menjadi angka (bilangan bulat) keseluruhan, mengabaikan karakter tambahan di bagian akhir. Begitu parseInt("10x")juga 10; yang xdiabaikan. Mendukung argumen radix (angka dasar) opsional, demikian parseInt("15", 16)juga 21( 15dalam hex). Jika tidak ada radix, asumsikan desimal kecuali string dimulai dengan 0x(atau 0X), dalam hal ini dilewati dan diasumsikan hex. (Beberapa browser digunakan untuk memperlakukan string yang dimulai dengan 0oktal; perilaku itu tidak pernah ditentukan, dan secara khusus tidak diizinkan dalam spesifikasi ES5.) Kembali NaNjika tidak ditemukan angka yang dapat diuraikan .

  • parseFloat(str)- Suka parseInt, tetapi apakah angka floating-point dan hanya mendukung desimal. Lagi karakter tambahan pada string diabaikan, begitu parseFloat("10.5x")juga 10.5( xdiabaikan). Karena hanya desimal yang didukung, parseFloat("0x15")adalah 0(karena parsing berakhir pada x). Kembali NaNjika tidak ditemukan angka yang dapat diuraikan.

  • Unary +, eg +str- (Misalnya, konversi implisit) Mengubah seluruh string menjadi angka menggunakan floating point dan notasi angka standar JavaScript (hanya digit dan titik desimal = desimal; 0xawalan = hex; 0oawalan = oktal [ES2015 +]; beberapa implementasi memperpanjangnya untuk memperlakukan pemimpin 0sebagai oktal, tetapi tidak dalam mode ketat). +"10x"adalah NaNkarena xini tidak diabaikan. +"10"is 10, +"10.5"is 10.5, +"0x15"is 21, +"0o10"is 8[ES2015 +]. Memiliki gotcha: +""adalah 0, tidak NaNseperti yang Anda harapkan.

  • Number(str)- Tepat seperti konversi implisit (misalnya, seperti unary di +atas), tetapi lebih lambat pada beberapa implementasi. (Bukan berarti itu penting.)

TJ Crowder
sumber
8
Jadi parseIntpertama digunakan toStringpada argumen pertama? Itu masuk akal.
evolutionxbox
16
@evolutionxbox: Yup, ini adalah langkah pertama dari parseIntalgoritma: ecma-international.org/ecma-262/7.0/…
TJ Crowder
5
Saya kira 123e-2memberi 1karena berubah menjadi 1.23pertama, dan kemudian parsing berhenti pada titik desimal?
ilkkachu
6
"Ini adalah sesuatu yang sering dilalui orang, bahkan ketika mereka mengetahuinya" -> apakah aku satu-satunya yang berpikir ini adalah bug? Melakukan hal yang sama di Jawa misalnya akan memberi Anda NumberFormatExceptionwaktu.
Wim Deblauwe
4
@SvenMarnach: Itu bagian dari parseInt(memaksa argumen pertama untuk string) masuk akal. Tujuannya parseIntadalah untuk mengurai string ke seluruh nomor. Jadi, jika Anda memberikannya sesuatu yang bukan string, mendapatkan representasi string untuk memulai dengan masuk akal. Apa yang dilakukannya setelah itu adalah keseluruhan cerita nother ...
TJ Crowder
54

Untuk alasan yang sama itu

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

Dalam dokumen tersebut , parseIntambil string. Dan

Jika string bukan string, maka itu dikonversi ke string

Jadi 16,, 8atau '1foobar'dikonversi terlebih dahulu ke string.

Kemudian

Jika parseIntmenemukan karakter yang bukan angka dalam radix yang ditentukan, ia mengabaikannya dan semua karakter berikutnya

Berarti itu mengkonversi ke mana ia bisa. The 6,, 8dan foobardiabaikan, dan hanya apa yang sebelumnya yang dikonversi. Jika tidak ada apa-apa, NaNdikembalikan.

njzk2
sumber
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]

Beberapa contoh lagi:

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 
SridharKritha
sumber