Как мне обойти восьмеричное поведение parseInt в JavaScript?

283

Попробуйте выполнить следующее в 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 думает, что ведущий ноль указывает восьмеричное целое число , и, поскольку в base-8 нет "8"ни одного, или "9"функция возвращает ноль. Как ни крути, это по замыслу .

Какие обходные пути?

Примечание. Для полноты картины я собираюсь опубликовать решение, но это решение, которое я ненавижу, поэтому, пожалуйста, публикуйте другие / лучшие ответы.


Обновить:

В 5-м издании стандарта JavaScript ( ECMA-262 ) вводятся серьезные изменения, устраняющие это поведение. У Mozilla хорошая рецензия .

Портман
источник
21
Шаг 1) Сделайте себе одолжение и всегда включайте основание, как упомянуто в предыдущих ответах, а также в книге Дуга. Шаг 2) Если вы серьезно относитесь к изучению JavaScript, то получите себе книгу Дуга. Это бесценно. Моя любимая книга до сих пор. Вот вам обзор: realtech.burningbird.net/learning-javascript/basics/…
fuentesjr
8
В браузерах, совместимых с ECMAScript 5-го издания, таких как Internet Explorer 9, для базового параметра по умолчанию используется значение 10(десятичное), если только перед анализируемым числом не указан префикс 0x, например 0xFF, в этом случае для базового параметра по умолчанию установлено значение 16. Надеюсь, однажды эта проблема будет далеким воспоминанием.
Энди Э
2
Как насчет просто +'08' === 8? Правда! Может быть, вам действительно нужен parseIntваш реальный код, но не выше.
Кодзиро
1
а) это не ошибка, исправьте заголовок б)Number('08')
OnTheFly
4
@portman: «5-е издание ... вносит серьезное изменение, которое устраняет это поведение». Вероятно, стоит отметить, что даже в 3-м издании (13 лет назад) реализации «поощряли» не делать этого: «Когда основание 0или undefinedи номер строки начинается с 0цифры, за которой не следует xни « X, ни» , тогда реализация может по своему усмотрению интерпретировать число как восьмеричное или как десятичное. В этом случае реализации рекомендуется интерпретировать числа как десятичные. " ( мой акцент)
TJ Crowder

Ответы:

329

Это распространенная ошибка в Javascript с простым решением:

Просто укажите основание , или 'основание', вот так:

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

Вы также можете использовать номер :

Number('08'); // 8
Паоло Бергантино
источник
57
Номер . Славный.
Портман
10
Number нужно заключать в кавычки около 08. Также просто предупреждаем, что Number ('08 .123 ') выдаст 8.123 в качестве выходных данных. Если вам действительно нужно целое число, не используйте Number (или сопоставляйте шаблон с вашим вводом, чтобы гарантировать только целые числа).
Джейсон С
3
Число (08); дает мне 8 в Firefox и IE.
Паоло Бергантино,
3
это не часть стандарта ECMAscript. Я тестирую JSDB, который использует Spidermonkey 1.7 (= движок Firefox JS) и жалуется, что «08 не является допустимой восьмеричной константой ECMA-262»
Jason S
5
Тем не менее, используйте «08» в кавычках. 08 не соответствует стандарту ECMA-262 и не гарантирует успешность без предупреждений и / или ошибок, и / или определенного указанного поведения.
Джейсон С
43

Если вы знаете, что ваше значение будет находиться в 32-разрядном целочисленном диапазоне со знаком , тогда все ~~xбудет правильно.

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

Если вы посмотрите двоичный файл not ( ~), спецификация требует преобразования «ToInt32» для аргумента, который выполняет очевидное преобразование в Int32 и определено для приведения NaNзначений к нулю.

Да, это невероятно хакерски, но так удобно ...

Карл Гертин
источник
2
Зачем две операции, когда одного бинарного или бы хватило?
Волков Олег Викторович
@ Олег, чего бы хватило?
Себастьян
3
@SebastianGodelet, | 0.
Олег Васильевич Волков
@Grodriguez, а когда 0 в | 0 это строка?
Волков Олег Васильевич
Весь этот вопрос об альтернативах parseInt для преобразования строк в целые числа. Таким образом: всегда.
Гродригес
24

Из документации parseInt используйте необязательный аргумент radix, чтобы указать base-10:

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

Это кажется мне педантичным, запутанным и многословным (действительно, дополнительный аргумент в каждом отдельном parseInt?), Поэтому я надеюсь, что есть лучший путь.

Портман
источник
6
если вам не нравится многословие, просто создайте свою собственную функцию, которая вызывает встроенную функцию и заполняет аргументы, которые вы всегда сохраняете постоянными.
Джейсон С
3
Riiiiiiight, потому что не каждый человек в StackOverflow ругает вас за написание функции parseIntB10. Написание собственной функции-оболочки - ужасная идея для этой цели.
Стефан Кендалл
2
@iftrue: я думаю, ты упустил мою точку зрения. Лично я не возражаю просто делать parseInt (someString, 10) везде, чтобы убедиться, что я форсирую базу 10. Похоже, что OP не нравится этот подход, поэтому я предложил альтернативу, которую лично я бы не использовал, но, возможно, она соответствует его необходимо. (Это, очевидно, и есть идея JQuery: сделать ее удобной, добавив дополнительную сложность. Я не использую JQuery, но многие считают ее полезной.)
Jason S
4
На самом деле это очень важно , чтобы обернуть parseIntдля удобного использования в функциональных выражениях, как mapв ["7","4","09","5"].map(parseInt); Mapпроедут индекс элемента в массиве в качестве второго аргумента, который будет интерпретироваться parseIntкак базовый, если вы не заключите его в обертку.
Plynx
11
function parseDecimal(s) { return parseInt(s, 10); }

edit: сделать свою собственную функцию, делать то, что вы действительно хотите, это просто вариант, если вам не нравится все время добавлять ", 10" в вызов parseInt (). Недостатком является нестандартная функция: она удобнее для вас, если вы часто ее используете, но, возможно, больше сбивает с толку других.

Джейсон С
источник
10

Укажите базу:

var number = parseInt(s, 10);
RichieHindle
источник
Вау, ребята, вы быстры. У меня даже был мой ответ в буфере обмена. Вы подключены напрямую к Интернету в нео-стиле?
Портман
1
Почему, черт возьми, это не по умолчанию на базе 10
Том Гуллен
2
Может быть потому, что она не предназначена в первую очередь как функция преобразования String-> Number, а как функция, которая считывает Number из базовой строки St.
artistoex
2
по умолчанию он равен основанию 10, но начальные нули являются широко распространенным способом обозначения восьмеричного числа.
Натан,
7

Было бы очень непослушно заменить parseInt версией, которая предполагает десятичность, если у нее нет второго параметра? (примечание - не проверено)

parseIntImpl = parseInt
parseInt = function(str, base){return parseIntImpl(str, base ? base : 10)}
Эндрю Даффи
источник
2
да, это было бы непослушно - это нарушило бы другой код, основанный на стандартном поведении.
jes5199
4
Это правда, но это не так много. Это также не стандартное поведение - восьмеричная поддержка не обязательна.
Эндрю Даффи
2
Но вы также отказываетесь от шестнадцатеричной поддержки, которая не является обязательной, не так ли? Это всегда должно быть правдой: parseInt("0xFFFFFF") === 16777215но с твоим непослушным хакером это больше не работаетparseInt("0xFFFFFF") === 0
Тимо
6

Вы также можете вместо использования parseFloat или parseInt использовать унарный оператор ( + ).

+"01"
// => 1

+"02"
// => 2

+"03"
// => 3

+"04"
// => 4

+"05"
// => 5

+"06"
// => 6

+"07"
// => 7

+"08"
// => 8

+"09"
// => 9

и для хорошей меры

+"09.09"
// => 9.09

MDN Link

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

SoEzPz
источник
5

Как насчет этого для десятичной:

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

('009'-0) === 9 // true
Гордон К
источник
4

Если вы уже выполнили кучу кодирования с помощью 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» - просто создает больше возможностей для ошибок.

ingredient_15939
источник
0

Эта проблема не может быть воспроизведена в последних версиях Chrome и Firefox (2019).

Андрия
источник