Làm cách nào để tôi làm việc xung quanh hành vi bát phân của JavaScript?


282

Hãy thử thực hiện các thao tác sau trong JavaScript:

parseInt('01'); //equals 1
parseInt('02'); //equals 2
parseInt('03'); //equals 3
parseInt('04'); //equals 4
parseInt('05'); //equals 5
parseInt('06'); //equals 6
parseInt('07'); //equals 7
parseInt('08'); //equals 0 !!
parseInt('09'); //equals 0 !!

Tôi vừa học được một cách khó khăn khi JavaScript nghĩ số 0 đứng đầu chỉ ra một số nguyên bát phân và vì không có "8"hoặc "9"trong cơ sở 8, nên hàm trả về 0. Dù muốn hay không, đây là do thiết kế .

Cách giải quyết là gì?

Lưu ý: Để hoàn thiện, tôi sắp đăng một giải pháp, nhưng đó là một giải pháp mà tôi ghét, vì vậy vui lòng đăng các câu trả lời khác / tốt hơn.


Cập nhật:

Phiên bản thứ 5 của tiêu chuẩn JavaScript ( ECMA-262 ) giới thiệu một thay đổi đột phá giúp loại bỏ hành vi này. Mozilla có một bài viết tốt .


21
Bước 1) Tự mình làm và luôn bao gồm cơ số như được đề cập trong các câu trả lời trước cũng như trong cuốn sách của Doug. Bước 2) Nếu bạn nghiêm túc về việc học JavaScript, hãy lấy cho mình một bản sao của cuốn sách Doug. Nó là vô giá. Cuốn sách fav của tôi cho đến nay. Dưới đây là một đánh giá fyi: realtech.burningbird.net/learning-javascript/basics/iêu
fuentesjr

8
Trong các trình duyệt tương thích với Phiên bản 5 của ECMAScript, như Internet Explorer 9, tham số cơ sở mặc định là 10(thập phân) trừ khi số để phân tích cú pháp được đặt trước 0x, ví dụ 0xFF, trong trường hợp đó, tham số cơ sở mặc định là 16. Hy vọng, một ngày nào đó, vấn đề này sẽ là một ký ức xa xôi.
Andy E

2
Thế còn +'08' === 8? Thật! Có thể bạn thực sự cần parseIntcho mã thực sự của bạn, nhưng không phải cho ở trên.
kojiro

1
a) đây không phải là lỗi, hãy sửa tiêu đề b)Number('08')
OnTheFly

4
@portman: "Phiên bản thứ 5 ... giới thiệu một thay đổi đột phá giúp loại bỏ hành vi này" Có lẽ đáng để chỉ ra rằng ngay cả trong phiên bản thứ 3 (13 năm trước), các triển khai đã được "khuyến khích" không thực hiện: "Khi radix là 0hoặc undefinedvà số của chuỗi bắt đầu bằng một 0chữ số không được theo sau bởi xhoặc Xsau đó, việc triển khai có thể, theo quyết định của nó, diễn giải số đó là số bát phân hoặc là số thập phân. Việc triển khai được khuyến khích diễn giải các số trong trường hợp này là số thập phân. " ( nhấn mạnh của tôi)
TJ Crowder

Câu trả lời:


328

Đây là một Gotcha Javascript phổ biến với một giải pháp đơn giản:

Chỉ cần chỉ định cơ sở , hoặc 'cơ số', như vậy:

parseInt('08',10); // 8

Bạn cũng có thể sử dụng Số :

Number('08'); // 8

57
Số . Vinh quang.
Portman

10
Số cần báo giá vào khoảng 08. Cũng cần được cảnh báo, Số ('08 .123 ') sẽ tạo ra 8.123 làm đầu ra. Nếu bạn thực sự muốn một số nguyên, không sử dụng Số (hoặc khớp mẫu của bạn để đảm bảo chỉ số nguyên).
Jason S

3
Số (08); cho tôi 8 cái trong Firefox và IE.
Paolo Bergantino

3
nó không phải là một phần của tiêu chuẩn ECMAscript. Tôi đang thử nghiệm trên JSDB sử dụng Spidermonkey 1.7 (= Firefox JS engine) và phàn nàn "08 không phải là hằng số bát phân ECMA-262 hợp pháp"
Jason S

5
Tuy nhiên, sử dụng '08' trong dấu ngoặc kép. 08 không đáp ứng tiêu chuẩn ECMA-262 và không được bảo đảm để thành công với các cảnh báo và / hoặc lỗi và / hoặc một hành vi được chỉ định cụ thể.
Jason S

43

nếu bạn biết giá trị của mình sẽ nằm trong phạm vi số nguyên 32 bit đã ký, thì ~~xsẽ thực hiện đúng trong tất cả các kịch bản.

~~"08" === 8
~~"foobar" === 0
~~(1.99) === 1
~~(-1.99)  === -1

Nếu bạn tra cứu nhị phân không ( ~), thông số kỹ thuật yêu cầu chuyển đổi "ToInt32" cho đối số thực hiện chuyển đổi rõ ràng thành Int32 và được chỉ định để ép buộcNaN các giá trị về 0.

Vâng, điều này là vô cùng hackish nhưng rất tiện lợi ...


2
Tại sao hai hoạt động khi một nhị phân hoặc sẽ đủ?
Oleg V. Volkov

@Oleg, Tại sao một người sẽ đủ?
Sebastian

3
@SebastianGodelet, | 0.
Oleg V. Volkov

@Grodriguez, và khi 0 trong | 0 là một chuỗi?
Oleg V. Volkov

Toàn bộ câu hỏi này là về các lựa chọn thay thế cho parseInt để chuyển đổi chuỗi thành số nguyên. Như vậy: luôn luôn.
Grodriguez

24

Từ tài liệu parseInt , sử dụng đối số cơ số tùy chọn để chỉ định cơ sở 10:

parseInt('08', 10); //equals 8
parseInt('09', 10); //equals 9

Điều này gây ấn tượng với tôi như là mô phạm, khó hiểu và dài dòng (thực sự, một cuộc tranh luận thêm trong mỗi phân tích đơn lẻ?) Vì vậy tôi hy vọng có một cách tốt hơn.


6
nếu bạn không thích Verbosity thì chỉ cần tạo hàm riêng gọi hàm dựng sẵn và điền vào các đối số bạn luôn giữ không đổi.
Jason S

3
Riiiiiiight, vì không giống như mọi người trên StackOverflow sẽ đánh cược bạn vì đã viết hàm parseIntB10. Viết chức năng bao bọc của riêng bạn là một ý tưởng khủng khiếp cho mục đích này.
Stefan Kendall

2
@iftrue: Tôi nghĩ bạn đã bỏ lỡ quan điểm của tôi. Cá nhân tôi không ngại chỉ thực hiện parseInt (someString, 10) ở mọi nơi để đảm bảo rằng tôi buộc căn cứ 10. OP dường như không thích cách tiếp cận này, vì vậy tôi đã đề xuất một giải pháp thay thế, mà tôi sẽ không sử dụng cá nhân nhưng có lẽ nó đáp ứng nhu cầu. (đây rõ ràng là suy nghĩ đằng sau JQuery: làm cho nó thuận tiện bằng cách thêm độ phức tạp. Tôi không sử dụng JQuery nhưng nhiều người thấy nó hữu ích.)
Jason S

4
Trên thực tế, việc bọc parseIntđể sử dụng thuận tiện trong các biểu thức chức năng là rất quan trọng , như mapin ["7","4","09","5"].map(parseInt); Mapsẽ chuyển chỉ mục của phần tử trong mảng làm đối số thứ hai, sẽ được hiểu parseIntlà cơ sở trừ khi bạn bọc nó.
Plynx

11
function parseDecimal(s) { return parseInt(s, 10); }

chỉnh sửa: tạo chức năng của riêng bạn, để làm những gì bạn thực sự muốn, chỉ là một tùy chọn nếu bạn không muốn thêm ", 10" mọi lúc vào lệnh gọi parseInt (). Nó có nhược điểm là chức năng không đạt tiêu chuẩn: thuận tiện hơn cho bạn nếu bạn sử dụng nó nhiều, nhưng có lẽ khó hiểu hơn cho người khác.


10

Chỉ định cơ sở:

var number = parseInt(s, 10);

Wow các bạn nhanh thật. Tôi thậm chí đã có câu trả lời của tôi trên clipboard. Bạn có cắm trực tiếp vào Internet, kiểu Neo không?
Portman

1
Tại sao ác quỷ không được mặc định là căn cứ 10
Tom Gullen

2
Có thể bởi vì nó không chủ yếu có nghĩa là một hàm chuyển đổi Chuỗi-> Số, mà là một hàm đọc một Số từ một chuỗi số b cơ sở.
artistoex

2
nó được mặc định là cơ sở 10 nhưng các số 0 đứng đầu là một cách phổ biến để biểu thị bát phân.
Nathan

7

Sẽ rất nghịch ngợm khi thay thế parseInt bằng một phiên bản giả định thập phân nếu nó không có tham số thứ hai? (lưu ý - không được kiểm tra)

parseIntImpl = parseInt
parseInt = function(str, base){return parseIntImpl(str, base ? base : 10)}

2
vâng, điều đó sẽ là nghịch ngợm - nó sẽ phá vỡ các mã khác dựa trên hành vi tiêu chuẩn.
jes5199

4
Đó là sự thật, nhưng không có nhiều điều đó. Nó cũng không phải là hành vi tiêu chuẩn - hỗ trợ bát phân là tùy chọn.
Andrew Duffy

2
Nhưng bạn cũng bỏ hỗ trợ hex không phải là tùy chọn, phải không? Điều này luôn luôn đúng: parseInt("0xFFFFFF") === 16777215nhưng với bản hack nghịch ngợm của bạn, nó không còn hoạt động nữaparseInt("0xFFFFFF") === 0
Timo


6

Bạn cũng có thể, thay vì sử dụng parseFloat hoặc parseInt, hãy sử dụng toán tử đơn nguyên ( + ).

+"01"
// => 1

+"02"
// => 2

+"03"
// => 3

+"04"
// => 4

+"05"
// => 5

+"06"
// => 6

+"07"
// => 7

+"08"
// => 8

+"09"
// => 9

và cho các biện pháp tốt

+"09.09"
// => 9.09

Liên kết MDN

Toán tử unary plus có trước toán hạng của nó và đánh giá toán hạng của nó nhưng cố gắng chuyển đổi nó thành một số, nếu nó chưa có. Mặc dù phủ định unary (-) cũng có thể chuyển đổi các số không, nhưng unary plus là cách nhanh nhất và được ưa thích để chuyển đổi một số thành một số , bởi vì nó không thực hiện bất kỳ thao tác nào khác trên số.


5

Làm thế nào về điều này cho số thập phân:

('09'-0) === 9  // true

('009'-0) === 9 // true

4

Nếu bạn đã thực hiện một loạt mã hóa với parseInt và không muốn thêm ", 10" vào mọi thứ, bạn chỉ có thể ghi đè hàm để biến cơ sở 10 thành mặc định:

window._oldParseInt = window.parseInt;
window.parseInt = function(str, rad) {
    if (! rad) {
        return _oldParseInt(str, 10);
    }
    return _oldParseInt(str, rad);
};

Điều đó có thể gây nhầm lẫn cho một người đọc sau này, do đó, việc thực hiện hàm parseInt10 () có thể tự giải thích nhiều hơn. Cá nhân tôi thích sử dụng một chức năng đơn giản hơn là phải thêm ", 10" mọi lúc - chỉ tạo ra nhiều cơ hội hơn cho các lỗi.


0

Vấn đề này không thể được sao chép trong Chrome mới nhất cũng như Firefox (2019).

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.