Как мне обойти восьмеричное поведение parseInt в JavaScript?
Попробуйте выполнить следующее в 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 !!
Я только что усвоил сложный способ, которым JavaScript думает, что ведущий ноль указывает восьмеричное целое число, и поскольку "8"
или же "9"
в base-8 функция возвращает ноль. Как ни крути, это по замыслу.
Каковы обходные пути?
Примечание. Для полноты картины я собираюсь опубликовать решение, но это решение, которое я ненавижу, поэтому, пожалуйста, публикуйте другие / лучшие ответы.
Обновить:
В 5-м издании стандарта JavaScript ( ECMA-262) вводятся серьезные изменения, устраняющие это поведение. У Mozilla хорошая рецензия.
9 ответов
Это распространенная ошибка в Javascript с простым решением:
Просто укажите основание или "основание", вот так:
parseInt('08',10); // 8
Вы также можете использовать номер:
Number('08'); // 8
Если вы знаете, что ваше значение будет в диапазоне 32-разрядных целых чисел со знаком, то ~~x
будет делать правильные вещи во всех сценариях.
~~"08" === 8
~~"foobar" === 0
~~(1.99) === 1
~~(-1.99) === -1
Если вы посмотрите бинарный нет (~
) спецификация требует преобразования "ToInt32" для аргумента, который выполняет очевидное преобразование в Int32 и задано для принудительного NaN
значения до нуля.
Да, это невероятно хакерски, но так удобно...
Из документации parseInt используйте необязательный аргумент radix, чтобы указать base-10:
parseInt('08', 10); //equals 8
parseInt('09', 10); //equals 9
Это кажется мне педантичным, запутанным и многословным (действительно, дополнительный аргумент в каждом отдельном parseInt?), Поэтому я надеюсь, что есть лучший путь.
function parseDecimal(s) { return parseInt(s, 10); }
edit: сделать свою собственную функцию, делать то, что вы действительно хотите, это просто вариант, если вам не нравится все время добавлять ",10" в вызов parseInt(). Недостатком является нестандартная функция: она удобнее для вас, если вы часто ее используете, но, возможно, больше сбивает с толку других.
Было бы очень непослушно заменить parseInt версией, которая предполагает десятичность, если у нее нет второго параметра? (примечание - не проверено)
parseIntImpl = parseInt
parseInt = function(str, base){return parseIntImpl(str, base ? base : 10)}
Вы также можете вместо использования parseFloat или parseInt использовать унарный оператор (+).
+"01"
// => 1
+"02"
// => 2
+"03"
// => 3
+"04"
// => 4
+"05"
// => 5
+"06"
// => 6
+"07"
// => 7
+"08"
// => 8
+"09"
// => 9
и для хорошей меры
+"09.09"
// => 9.09
Унарный оператор плюс предшествует своему операнду и вычисляет его операнд, но пытается преобразовать его в число, если это еще не сделано. Хотя унарное отрицание (-) также может преобразовывать не числа, унарный плюс - это самый быстрый и предпочтительный способ преобразования чего-либо в число, поскольку он не выполняет никаких других операций над числом.
Как насчет этого для десятичной:
('09'-0) === 9 // true
('009'-0) === 9 // true
Если вы уже выполнили кучу кодирования с помощью parseInt и не хотите добавлять "10" ко всему, вы можете просто переопределить функцию, чтобы сделать base 10 по умолчанию:
window._oldParseInt = window.parseInt;
window.parseInt = function(str, rad) {
if (! rad) {
return _oldParseInt(str, 10);
}
return _oldParseInt(str, rad);
};
Это может сбить с толку более позднего читателя, поэтому создание функции parseInt10() может быть более понятным. Лично я предпочитаю использовать простую функцию, чем постоянно добавлять "10" - просто создает больше возможностей для ошибок.
Эту проблему нельзя воспроизвести ни в последних версиях Chrome, ни в Firefox (2019).