Tại sao parseInt (8.3) == NaN và parseInt (16,3) == 1?


191

Tôi đang đọc này nhưng tôi đang bối rối bởi những gì được viết trong parseInt với một đối số radix chương

bảng kết quả parseInt (_, 3)

Tại sao nó là parseInt(8, 3)NaNparseInt(16, 3)1?

AFAIK 8 và 16 là không cơ sở-3 số, vì vậy parseInt(16, 3)nên quay lại NaNquá

mười số tự nhiên cơ sở 3 đầu tiên


4
Tuy nhiên, một vấn đề khác đã được giải quyết bằng cách gõ tĩnh (hoặc ít nhất là không hoàn toàn chuyển đổi số nguyên thành chuỗi): P
Navin

4
@Navin Điều này không liên quan gì đến việc gõ tĩnh so với gõ động (như bạn tự lưu ý). Vấn đề ở đây là yếu so với gõ mạnh.
Sven Marnach

12
Khi tôi nhìn thấy tiêu đề của câu hỏi này, tôi đã nghĩ: "có lẽ là vì loljavascript". Nhìn thấy câu trả lời tôi đánh giá bản năng của tôi về cơ bản là chính xác.
Ben Millwood

Câu trả lời:


373

Đây là một cái gì đó mọi người đi qua tất cả các thời gian, ngay cả khi họ biết về nó. :-) Bạn đang thấy điều này với cùng lý do parseInt("1abc")trả về 1: parseIntdừng ở ký tự không hợp lệ đầu tiên và trả về bất cứ thứ gì nó có tại thời điểm đó. Nếu không có ký tự hợp lệ để phân tích cú pháp, nó sẽ trả về NaN.

parseInt(8, 3)có nghĩa là "phân tích cú pháp "8"trong cơ sở 3" (lưu ý rằng nó chuyển đổi số 8thành một chuỗi; chi tiết trong thông số kỹ thuật ). Nhưng trong cơ sở 3, số một con số chỉ là 0, 1, và 2. Nó giống như yêu cầu nó phân tích "9"theo bát phân. Vì không có ký tự hợp lệ, bạn có NaN.

parseInt(16, 3)đang yêu cầu nó phân tích cú pháp "16"trong cơ sở 3. Vì nó có thể phân tích cú pháp 1, nên nó dừng lại và 6vì nó không thể phân tích cú pháp. Thế là nó trở về 1.


Vì câu hỏi này đang thu hút nhiều sự chú ý và có thể xếp hạng cao trong kết quả tìm kiếm, nên đây là danh sách các tùy chọn để chuyển đổi chuỗi thành số trong JavaScript, với các ứng dụng và ứng dụng khác nhau (được lấy từ câu trả lời khác của tôi ở đây trên SO):

  • parseInt(str[, radix])- Chuyển đổi càng nhiều đầu chuỗi càng tốt thành số nguyên (số nguyên), bỏ qua các ký tự phụ ở cuối. Thế parseInt("10x")là xong 10; cái xbị bỏ qua. Hỗ trợ một đối số tùy chọn radix (số cơ sở), do đó parseInt("15", 16)21( 15trong hex). Nếu không có cơ số, giả sử thập phân trừ khi chuỗi bắt đầu bằng 0x(hoặc 0X), trong trường hợp đó, nó bỏ qua các chuỗi đó và giả sử hex. (Một số trình duyệt được sử dụng để xử lý các chuỗi bắt đầu bằng số 0bát phân; hành vi đó không bao giờ được chỉ định và đặc biệt không được phép trong đặc tả ES5.) Trả về NaNnếu không tìm thấy chữ số có thể phân tích được.

  • parseFloat(str)- Thích parseInt, nhưng không có số dấu phẩy động và chỉ hỗ trợ số thập phân. Một lần nữa nhân vật thêm vào chuỗi được bỏ qua, vì vậy parseFloat("10.5x")10.5(sự xbị bỏ qua). Vì chỉ có số thập phân được hỗ trợ, parseFloat("0x15")0(vì phân tích cú pháp kết thúc tại x). Trả về NaNnếu không tìm thấy chữ số phân tích được.

  • Unary +, ví dụ +str- (Ví dụ, chuyển đổi ngầm) Chuyển đổi toàn bộ chuỗi với một số sử dụng dấu chấm động và ký hiệu số tiêu chuẩn của JavaScript (chỉ số và một dấu thập phân = thập phân; 0xprefix = hex; 0oprefix = bát phân [ES2015 +]; một số triển khai mở rộng nó để coi một người dẫn đầu 0là bát phân, nhưng không ở chế độ nghiêm ngặt). +"10x"NaNbởi vì xkhông bỏ qua. +"10"10, +"10.5"10.5, +"0x15"21, +"0o10"8[ES2015 +]. Có một gotcha: +""0, không NaNnhư bạn mong đợi.

  • Number(str)- Chính xác như chuyển đổi ngầm định (ví dụ, như unary +ở trên), nhưng chậm hơn trên một số triển khai. (Không phải là nó có khả năng quan trọng.)


8
Vì vậy, parseIntlần đầu tiên sử dụng toStringtrên các đối số đầu tiên? Điều đó sẽ có ý nghĩa.
Evolutionxbox

16
@evolutionxbox: Yup, đây là bước đầu tiên của parseIntthuật toán: ecma
TJ Crowder

5
Tôi cho rằng 123e-2đưa ra 1vì nó biến thành 1.23đầu tiên, và sau đó phân tích cú pháp dừng ở dấu thập phân?
ilkkachu

6
"Đây là điều mọi người vấp phải mọi lúc, ngay cả khi họ biết về nó" -> tôi có phải là người duy nhất nghĩ rằng đây là một lỗi không? Làm tương tự trong Java chẳng hạn sẽ cho bạn một NumberFormatExceptionlần.
Wim Deblauwe

4
@SvenMarnach: Đó là một phần của parseInt(ép buộc đối số đầu tiên thành chuỗi) có ý nghĩa. Mục đích của parseInt phân tích một chuỗi thành một số nguyên. Vì vậy, nếu bạn cung cấp cho nó một cái gì đó không phải là một chuỗi, việc bắt đầu biểu diễn chuỗi của nó bắt đầu có ý nghĩa. Những gì nó làm sau đó là toàn bộ 'câu chuyện chưa từng thấy ...
TJ Crowder

54

Vì lý do tương tự mà

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

Trong tài liệu , parseIntcó một chuỗi. Và

Nếu chuỗi không phải là một chuỗi, thì nó được chuyển đổi thành một chuỗi

Vì vậy 16, 8hoặc '1foobar'lần đầu tiên được chuyển đổi thành chuỗi.

Sau đó

Nếu parseIntgặp một ký tự không phải là số trong cơ số được chỉ định, nó sẽ bỏ qua nó và tất cả các ký tự tiếp theo

Có nghĩa là nó chuyển đổi đến nơi nó có thể. Các 6, 8foobarđược bỏ qua, và chỉ những gì trước đó được chuyển đổi. Nếu không có gì, NaNđược trả lại.


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]

Một số ví dụ khác:

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 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.