Wie gehe ich um das parseInt-Oktalverhalten von JavaScript herum?

282

Versuchen Sie Folgendes in JavaScript auszuführen:

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 !!

Ich habe gerade auf die harte Tour gelernt, dass JavaScript denkt, dass die führende Null eine oktale Ganzzahl anzeigt , und da es keine "8"oder "9"in Basis-8 gibt, gibt die Funktion Null zurück. Ob es Ihnen gefällt oder nicht, dies ist beabsichtigt .

Was sind die Problemumgehungen?

Hinweis: Der Vollständigkeit halber werde ich eine Lösung veröffentlichen, aber es ist eine Lösung, die ich hasse. Bitte posten Sie andere / bessere Antworten.


Aktualisieren:

Die 5. Ausgabe des JavaScript-Standards ( ECMA-262 ) führt eine grundlegende Änderung ein, die dieses Verhalten beseitigt. Mozilla hat eine gute Zusammenfassung .

Portman
quelle
21
Schritt 1) ​​Tun Sie sich selbst einen Gefallen und geben Sie immer den Radix an, wie in den vorherigen Antworten sowie in Dougs Buch erwähnt. Schritt 2) Wenn Sie ernsthaft JavaScript lernen möchten, besorgen Sie sich eine Kopie von Dougs Buch. Es ist von unschätzbarem Wert. Mein Lieblingsbuch bisher. Hier ist eine Überprüfung fyi: realtech.burningbird.net/learning-javascript/basics/…
fuentesjr
8
In ECMAScript 5th Edition-kompatiblen Browsern wie Internet Explorer 9 ist der Basisparameter standardmäßig 10(dezimal), es sei denn, der zu analysierenden Zahl wird ein Präfix vorangestellt 0x, z. B. 0xFFin diesem Fall ist der Basisparameter standardmäßig 16. Hoffentlich eines Tages dieses Problem wird eine ferne Erinnerung sein.
Andy E
2
Wie wäre es einfach +'08' === 8? Wahr! Vielleicht brauchen Sie wirklich parseIntfür Ihren echten Code, aber nicht für die oben genannten.
Kojiro
1
a) Dies ist kein Fehler, Number('08')
korrigieren Sie
4
@portman: "Die 5. Ausgabe ... führt eine bahnbrechende Änderung ein, die dieses Verhalten beseitigt." Wahrscheinlich ist darauf hinzuweisen, dass Implementierungen bereits in der 3. Ausgabe (vor 13 Jahren) "ermutigt" wurden, dies nicht zu tun: "Wenn Radix 0oder ist undefinedund die Nummer der Zeichenfolge beginnt mit einer 0Ziffer, auf die kein xoder folgt, oder Xdie Implementierung kann die Nummer nach eigenem Ermessen entweder als oktal oder als dezimal interpretieren . Implementierungen werden empfohlen, Zahlen in diesem Fall als dezimal zu interpretieren. " ( meine Betonung)
TJ Crowder

Antworten:

328

Dies ist eine gängige Javascript-Gotcha mit einer einfachen Lösung:

Geben Sie einfach die Basis oder 'Radix' wie folgt an:

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

Sie können auch Number verwenden :

Number('08'); // 8
Paolo Bergantino
quelle
57
Nummer . Herrlich.
Portman
10
Die Zahl benötigt Anführungszeichen um die 08. Seien Sie auch gewarnt, die Zahl ('08 .123 ') erzeugt 8,123 als Ausgabe. Wenn Sie wirklich eine Ganzzahl möchten, verwenden Sie keine Zahl (oder passen Sie Ihre Eingabe an das Muster an, um nur Ganzzahlen sicherzustellen).
Jason S
3
Nummer (08); gibt mir 8 in Firefox und IE.
Paolo Bergantino
3
Es ist nicht Teil des ECMAscript-Standards. Ich teste auf JSDB, die Spidermonkey 1.7 (= Firefox JS-Engine) verwendet, und beschwere mich, dass "08 keine legale ECMA-262-Oktalkonstante ist"
Jason S
5
Verwenden Sie dennoch '08' in Anführungszeichen. 08 entspricht nicht dem ECMA-262-Standard und kann ohne Warnungen und / oder Fehler und / oder ein bestimmtes bestimmtes Verhalten nicht erfolgreich sein.
Jason S
43

Wenn Sie wissen, dass Ihr Wert im vorzeichenbehafteten 32-Bit-Ganzzahlbereich liegt, ~~xtun Sie in allen Szenarien das Richtige.

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

Wenn Sie binär not ( ~) nachschlagen , erfordert die Spezifikation eine "ToInt32" -Konvertierung für das Argument, das die offensichtliche Konvertierung in ein Int32 durchführt und angegeben wird, um NaNWerte auf Null zu zwingen .

Ja, das ist unglaublich hackisch, aber so praktisch ...

Karl Guertin
quelle
2
Warum zwei Operationen, wenn eine binär oder ausreichen würde?
Oleg V. Volkov
@Oleg, warum sollte man ausreichen?
Sebastian
3
@SebastianGodelet, | 0.
Oleg V. Volkov
@Grodriguez, und wenn 0 in | 0 eine Zeichenfolge ist?
Oleg V. Volkov
Bei dieser ganzen Frage geht es um Alternativen zu parseInt zum Konvertieren von Zeichenfolgen in Ganzzahlen. Also: immer.
Grodriguez
24

Verwenden Sie in der parseInt-Dokumentation das optionale radix-Argument, um base-10 anzugeben:

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

Das kommt mir pedantisch, verwirrend und wortreich vor (wirklich ein zusätzliches Argument in jeder einzelnen Analyse?), Also hoffe ich, dass es einen besseren Weg gibt.

Portman
quelle
6
Wenn Sie Verbosity nicht mögen, erstellen Sie einfach Ihre eigene Funktion, die die integrierte Funktion aufruft und die Argumente ausfüllt, die Sie immer konstant halten.
Jason S
3
Riiiiiiight, weil es nicht so ist, als würde jede einzelne Person auf StackOverflow Sie beschimpfen, wenn Sie die Funktion parseIntB10 schreiben. Das Schreiben einer eigenen Wrapper-Funktion ist zu diesem Zweck eine schreckliche Idee.
Stefan Kendall
2
@iftrue: Ich denke du hast meinen Standpunkt verfehlt. Es macht mir persönlich nichts aus, überall nur parseInt (someString, 10) zu machen, um sicherzustellen, dass ich Basis 10 erzwinge. Das OP scheint diesen Ansatz nicht zu mögen, deshalb schlug ich eine Alternative vor, die ich persönlich nicht verwenden würde, aber vielleicht entspricht sie seiner Bedürfnisse. (Dies ist anscheinend der Gedanke hinter JQuery: Machen Sie es bequem, indem Sie zusätzliche Komplexität hinzufügen. Ich verwende JQuery nicht, aber viele Leute finden es nützlich.)
Jason S
4
Tatsächlich ist es wirklich wichtig, parseIntfür die bequeme Verwendung in funktionalen Ausdrücken zu umbrechen , da mapin ["7","4","09","5"].map(parseInt); Mapden Index des Elements im Array als zweites Argument übergeben wird, das von parseIntals Basis interpretiert wird, sofern Sie es nicht umschließen.
Plynx
11
function parseDecimal(s) { return parseInt(s, 10); }

Bearbeiten: Eine eigene Funktion zu erstellen, um das zu tun, was Sie wirklich wollen, ist nur eine Option, wenn Sie dem parseInt () -Aufruf nicht immer die ", 10" hinzufügen möchten. Es hat den Nachteil, dass es sich um eine nicht standardmäßige Funktion handelt: Bequemer für Sie, wenn Sie sie häufig verwenden, aber für andere vielleicht verwirrender.

Jason S.
quelle
10

Geben Sie die Basis an:

var number = parseInt(s, 10);
RichieHindle
quelle
Wow ihr seid schnell. Ich hatte sogar meine Antwort in der Zwischenablage. Sind Sie im Neo-Stil direkt mit dem Internet verbunden?
Portman
1
Warum zum Teufel ist es nicht standardmäßig Basis 10
Tom Gullen
2
Vielleicht, weil es nicht primär als String-> Zahlenkonvertierungsfunktion gedacht ist, sondern als Funktion, die eine Zahl aus einem String der Basis-b-Zahl liest.
artistoex
2
Standardmäßig wird Basis 10 verwendet, aber führende Nullen sind eine weit verbreitete Methode, um Oktal anzuzeigen.
Nathan
7

Wäre es sehr ungezogen, parseInt durch eine Version zu ersetzen, die eine Dezimalzahl annimmt, wenn sie keinen zweiten Parameter hat? (Hinweis - nicht getestet)

parseIntImpl = parseInt
parseInt = function(str, base){return parseIntImpl(str, base ? base : 10)}
Andrew Duffy
quelle
2
Ja, das wäre ungezogen - es würde anderen Code beschädigen, der sich auf das Standardverhalten stützte.
jes5199
4
Das stimmt, aber davon gibt es nicht viel. Es ist auch kein Standardverhalten - Oktalunterstützung ist optional.
Andrew Duffy
2
Aber Sie lassen auch Hex-Unterstützung fallen, was nicht optional ist, oder? Dies sollte immer wahr sein:, parseInt("0xFFFFFF") === 16777215aber mit Ihrem ungezogenen Hack funktioniert es nicht mehrparseInt("0xFFFFFF") === 0
Timo
6

Sie können auch anstelle von parseFloat oder parseInt den unären Operator ( + ) verwenden.

+"01"
// => 1

+"02"
// => 2

+"03"
// => 3

+"04"
// => 4

+"05"
// => 5

+"06"
// => 6

+"07"
// => 7

+"08"
// => 8

+"09"
// => 9

und für ein gutes Maß

+"09.09"
// => 9.09

MDN Link

Der unäre Plus-Operator steht vor seinem Operanden und wertet ihn als Operanden aus, versucht jedoch, ihn in eine Zahl umzuwandeln, sofern dies noch nicht geschehen ist. Obwohl unäre Negation (-) auch Nicht-Zahlen konvertieren kann, ist unäres Plus die schnellste und bevorzugte Methode, um etwas in eine Zahl umzuwandeln , da keine anderen Operationen an der Zahl ausgeführt werden.

SoEzPz
quelle
5

Wie wäre es damit für Dezimalstellen:

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

('009'-0) === 9 // true
Gordon K.
quelle
4

Wenn Sie bereits mit parseInt eine Reihe von Codierungen vorgenommen haben und nicht zu allem ", 10" hinzufügen möchten, können Sie die Funktion einfach überschreiben, um Basis 10 als Standard festzulegen:

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

Dies kann einen späteren Leser verwirren, sodass das Erstellen einer parseInt10 () -Funktion möglicherweise selbsterklärender ist. Persönlich bevorzuge ich die Verwendung einer einfachen Funktion, anstatt ständig ", 10" hinzufügen zu müssen - dies schafft nur mehr Möglichkeiten für Fehler.

Zutat_15939
quelle
0

Dieses Problem kann weder in Chrome noch in Firefox (2019) repliziert werden.

Andrija
quelle