Почему parseInt ('dsff66', 16) возвращает 13?

сегодня я наткнулся на странный (на мой взгляд) дело в JavaScript. Я передал не шестнадцатеричную строку функции parseInt с базой 16 и...Я получил результат. Я ожидал бы, что функция выдаст какое-то исключение или, по крайней мере, вернет NaN, но ей удалось проанализировать его и вернуть int.

мой призыв был:

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

и вот результат: 13.

Я заметил, что он" останавливает " синтаксический анализ с первым символом, который не принадлежат к системе счисления, указанной во 2-м аргументе, поэтому вызываем parseInt('fg',16) Я бы 15 как результат.

на мой взгляд, он должен вернуть Нэн. Может кто-нибудь объяснить мне, почему это не так? Почему кто-то хочет, чтобы эта функция вела себя так (возвращала целое число, даже если это не точное представление переданной строки) ?

4 ответов


почему кто-то хочет, чтобы эта функция вела себя так (возвращала целое число, даже если это не точное представление переданной строки)?

потому что большую часть времени (на сегодняшний день) вы работаете с базовыми числами 10, и в этом случае JS может просто cast - не разбирать-строку на число. (edit: по-видимому, не только base-10; см. обновление ниже.)

поскольку JS динамически типизирован, некоторые строки работают просто отлично как числа без всякой работы с твоей стороны. Например:

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

не нужно parseInt, потому что "21" и "12.4" по существу уже являются числами. Однако если строка "12.4xyz" тогда вы действительно получите NaN при делении, так как это определенно не число и не может быть неявно брошено или принуждено к одному.

вы также можете явно "бросить" строку в число с Number(someString). в то время как он тоже поддерживает только базу 10, он действительно вернется NaN для недопустимых строк.

так как JS уже имеет неявный и явный тип литья / преобразования / принуждения,parseIntроль не должна быть еще одной функцией кастинга типа.

parseIntвместо этого роль должна быть, ну,извлечение


parseInt считывает входные данные, пока не встретит недопустимый символ, а затем использует все допустимые входные данные, прочитанные до этого недопустимого символа. Подумайте:

parseInt("17days", 10);

это будет использовать вход 17 и опустить все после недействительного d.

С спецификация ECMAScript:

если [входная строка] S содержит любой символ, который не является цифрой radix-R, то пусть Z [строка должна быть целочисленной] подстрока S, состоящая из всех символов перед первым таким символом; в противном случае пусть Z будет с.

в вашем примере s является недопустимым символом базы-16, поэтому parseInt использует только ведущие d.

как почему это поведение было включено: нет способа узнать наверняка, но это, скорее всего, попытка воспроизвести поведение strtol (string to long)из стандартной библиотеки C. От strtol(3) man page:

...строка преобразуется в длинное значение int очевидным образом,остановка на первом символе, который не является допустимой цифрой в данную базу.

это соединение дополнительно поддерживается (в некоторой степени) тем, что оба parseInt и strtol указаны, чтобы игнорировать ведущие пробелы, и они могут оба принимать ведущий 0x для шестнадцатеричных значений.


в данном случае parseInt() интерпретировать письмо от "A" to "F" as hexadecimal и разберите их на десятичные числа. Это значит d вернутся 13.

что делает parseInt ()

  • parseInt("string", radix) интерпретируйте числа и Буквы в строке как шестнадцатеричные (это зависит от радиуса) в число.

  • parseInt() только разобрать число или букву как шестнадцатеричное от начала строки пока недопустимый символ как шестнадцатеричный.

  • если parseInt() не удается найти число или букву как шестнадцатеричную в начале строки parseInt() вернутся Нэн.

  • если радиус не определен, то он равен 10.

  • если строка начинается с "0x", основание 16.

  • если радиус определен 0, основание 10.

  • Если основание 1, parseInt() возврат NaN.

  • Если основание 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" до "9" и/или "A" to "Z".

  • если символы интерпретируются как шестнадцатеричные более одного, каждый символ будет иметь разное значение, хотя эти символы являются одним и тем же символом. например,parseInt("AA", 11) первый "A" имеет другое значение со вторым "A".

  • другой radix вернет другой номер, хотя строки одинаковы строка.

посмотреть его в действии

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";

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 является шестнадцатеричным символом (даже если строка не является шестнадцатеричной), который соответствует типу radix и эквивалентен number 13. После этого он перестает анализировать, так как следующий символ не является шестнадцатеричным, следовательно, результат.