Ответ 1
Это обычная версия Javascript с простым решением:
Просто укажите базу или "radix", например:
parseInt('08',10); // 8
Вы также можете использовать Number:
Number('08'); // 8
Попробуйте выполнить следующее в 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"
в базе-8 функция возвращает ноль. Нравится вам это или нет, это по дизайну.
Каковы обходные пути?
Примечание. Для полноты я собираюсь опубликовать решение, но это решение, которое я ненавижу, поэтому, пожалуйста, напишите другие/лучшие ответы.
Обновление:
5-е издание стандарта JavaScript (ECMA-262) вводит нарушение, которое устраняет это поведение. Mozilla имеет хорошую запись.
Это обычная версия Javascript с простым решением:
Просто укажите базу или "radix", например:
parseInt('08',10); // 8
Вы также можете использовать Number:
Number('08'); // 8
Прежде всего, в большинстве случаев вам действительно не нужно parseInt()
. Этот алгоритм полон различных причуд, префикс 0
даже запрещен спецификацией ( "спецификация функции parseInt больше не позволяет реализации для обработки строк, начинающихся с символа 0 как восьмеричные значения." ), но потребуется некоторое время, чтобы изменить поведение браузера (даже если я что никто не использует восьмеричные намеренно в parseInt()
). И Internet Explorer 6 никогда не изменится (Internet Explorer 9, однако, удалил поддержку восьмеричных в parseInt()
). Используемый им алгоритм обычно делает больше, чем вы хотите от него. В некоторых случаях это плохая идея.
' 4'
становится '4'
.-
или +
и удаляется этот символ. Если это было -
, выход отрицательный.0
или NaN
попытайтесь угадать radix. Это означает поиск (без учета регистра) для 0x
и (нестандартного) 0
. Если префикс не найден, используется 10
(и это то, что вы, скорее всего, что).16
strip 0x
с самого начала, если он существует.NaN
.Преобразуйте число до десятичного числа до первого символа, который не находится в диапазоне.
Например, parseInt('012z', 27)
дает 0 * Math.pow(27, 2) + 1 * Math.pow(27, 1) + 2 * Math.pow(27, 0)
.
Сам алгоритм не очень быстрый, но производительность меняется (оптимизация делает чудеса). Я положил тест на JSPerf, и результаты были интересными. +
и ~~
являются самыми быстрыми с исключением для Chrome, где parseFloat()
как-то быстрее, чем другие параметры (в 2-5 раз быстрее, чем другие параметры, где +
на самом деле в 5 раз медленнее). В Firefox тест ~~
выполняется очень быстро - в некоторых случаях у меня есть циклы Infinity
.
Другое дело - правильность. parseInt()
, ~~
и parseFloat()
делают ошибки молчащими. В случае parseInt()
и parseFloat()
символы игнорируются после недопустимого символа - вы можете назвать это функцией (в большинстве случаев это анти-функция для меня, так же как и инструкции switch
), и если вам это нужно, используйте один из тех. В случае ~~
это означает возврат 0
, поэтому будьте осторожны.
В некоторых случаях parseInt()
может навредить вам. Плохо. Например, если число настолько велико, что оно записано в экспоненциальной нотации. Затем используйте методы Math
.
parseInt(2e30); // will return 2
В любом случае, в конце я хочу создать список методов для преобразования строк в числа (как целые, так и плавающие). У них есть различные способы использования, и вам может быть интересно, какой метод использовать. В большинстве случаев самый простой метод +number
, используйте его, если можете. Что бы вы ни делали (кроме первого метода), все должны давать правильный результат.
parseInt('08', 10); // 8
+'08'; // 8
~~'08'; // 8
parseFloat('08'); // 8
Number('08'); // 8
new Number('08'); // 8... I meant Object container for 8
Math.ceil('08'); // 8
parseInt(number)
Не использовать. Просто как тот. Либо используйте parseInt(number, 10)
, либо это обходное решение, которое волшебным образом исправит функцию parseInt
. Обратите внимание, что это обходное решение не будет работать в JSLint. Пожалуйста, не жалуйтесь на это.
(function () {
"use strict";
var oldParseInt = parseInt;
// Don't use function parseInt() {}. It will make local variable.
parseInt = function (number, radix) {
return oldParseInt(number, radix || 10);
};
}());
parseInt(number, radix)
parseInt
преобразует аргумент в числа, используя упомянутый выше алгоритм. Избегайте использования его на больших целых числах, так как он может делать неправильные результаты в таких случаях, как parseInt(2e30)
. Кроме того, никогда не давайте в качестве аргумента для изменения Array.prototype.map
или Underscore.js, поскольку вы можете получить странные результаты (попробуйте ['1', '2', '3'].map(parseInt)
, если хотите (для пояснения замените parseInt
на console.log
)).
Используйте его, если:
123px
на 123
)В противном случае используйте другие более безопасные методы (если вам нужно целое число, используйте Math.floor
).
+number
+
(+number
) преобразует число в float. В случае ошибки он возвращает NaN
, который вы можете сравнить либо с помощью isNaN()
, либо просто с помощью number !== number
(он должен возвращать true
только для NaN
). Это очень быстро в Opera.
Используйте его, если вы не хотите использовать специальные функции других типов.
~~number
~~
- это хак, который использует ~
два раза на целое число. Поскольку ~
побитовая операция может выполняться только для целых чисел, число автоматически преобразуется. У большинства браузеров есть оптимизация для этого случая. Поскольку побитовые операции работают только ниже Math.pow(2, 32)
, никогда не используйте этот метод с большими числами. Он невероятно быстро работает на двигателе SpiderMonkey.
Используйте его, если:
parseFloat(number)
parseFloat()
работает как +
с одним исключением - он обрабатывает номер до первого недопустимого символа вместо возврата NaN
. Это очень быстро (но не так быстро, как ~~
в Firefox) в V8. В отличие от изменения parseInt
, он должен быть безопасным с Array.prototype.map
.
Используйте его, если:
42.13px
на 42.13
)Number(number)
Избегайте этого. Он работает как префикс +
и обычно медленнее. Единственное использование, где это может быть полезно, это обратный вызов для Array.prototype.map
- вы не можете использовать +
как обратный вызов.
new Number(number)
Используйте его, когда вам нужно путать всех с 0
, являющимся истинным значением и имеющим typeof
of 'number'
. Серьезно, не делайте.
Math.ceil(number)
Используйте их, когда вам нужно целое число, более безопасное, чем parseInt()
, не игнорируя неожиданные символы. Обратите внимание, что технически это связано с длинным преобразованием - строка → float → integer → float (числа в JavaScript - это float), но у большинства браузеров есть оптимизация для него, поэтому обычно это не так заметно. Он также безопасен с Array.prototype.map
.
Если вы знаете, ваше значение будет в 32-битном целочисленном диапазоне, то ~~x
выполнит правильную работу во всех сценариях.
~~"08" === 8
~~"foobar" === 0
~~(1.99) === 1
~~(-1.99) === -1
Если вы ищете двоичный файл not (~
), для спецификации требуется преобразование "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(). Недостатком является нестандартная функция: более удобна для вас, если вы используете ее много, но, возможно, более запутанную для других.
Укажите базу:
var number = parseInt(s, 10);
Было бы очень непослушно заменять parseInt версией, которая принимает десятичное значение, если у нее нет второго параметра? (примечание - не проверено)
parseIntImpl = parseInt
parseInt = function(str, base){return parseIntImpl(str, base ? base : 10)}
Как насчет этого для десятичного числа:
('09'-0) === 9 // true
('009'-0) === 9 // true
Вы также можете вместо использования parseFloat или parseInt использовать унарный оператор (+).
+"01"
// => 1
+"02"
// => 2
+"03"
// => 3
+"04"
// => 4
+"05"
// => 5
+"06"
// => 6
+"07"
// => 7
+"08"
// => 8
+"09"
// => 9
и для хорошей меры
+"09.09"
// => 9.09
Унарный оператор плюс предшествует своему операнду и вычисляет его операнд, но пытается преобразовать его в число, если это еще не сделано. Хотя унарное отрицание (-) также может преобразовывать не числа, унарный плюс - это самый быстрый и предпочтительный способ преобразования чего-либо в число, поскольку он не выполняет никаких других операций над числом.
Если вы уже сделали кучу кодирования уже с parseInt и не хотите добавлять ", 10" ко всему, вы можете просто переопределить эту функцию, чтобы сделать базу 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).