JavaScript hat einen einzigen Typ für alle Zahlen: es behandelt sie alle als Fließkommazahlen. Der Punkt wird jedoch nicht angezeigt, wenn keine Ziffern nach dem Dezimalpunkt stehen:
> 5.000 5
Intern optimieren die meisten JavaScript-Engines und unterscheiden zwischen Fließkommazahlen und ganzen Zahlen (Details: Ganze Zahlen in JavaScript). Aber das ist etwas, das Programmierer nicht sehen.
JavaScript-Zahlen sind double (64-Bit)-Werte, basierend auf dem IEEE-Standard für Fließkomma-Arithmetik (IEEE 754). Dieser Standard wird von vielen Programmiersprachen verwendet.
Ein Zahlenliteral kann eine ganze Zahl, eine Fließkommazahl oder eine (ganzzahlige) Hexadezimalzahl sein:
> 35 // integer 35 > 3.141 // floating point 3.141 > 0xFF // hexadecimal 255
Ein Exponent, eX, ist eine Abkürzung für „multipliziere mit 10X“:
> 5e2 500 > 5e-2 0.05 > 0.5e2 50
Bei Zahlenliteralen muss der Punkt für den Zugriff auf eine Eigenschaft vom Dezimalpunkt unterschieden werden. Dies gibt Ihnen die folgenden Optionen, wenn Sie toString() auf dem Zahlenliteral 123 aufrufen möchten:
123..toString()123.toString()// space before the dot123.0.toString()(123).toString()
Werte werden wie folgt in Zahlen umgewandelt:
| Wert | Ergebnis |
|
|
|
|
Ein boolescher Wert |
|
| |
Eine Zahl | Identisch mit der Eingabe (keine Konvertierung erforderlich) |
Ein String | Parsen der Zahl in der Zeichenkette (ignorieren von führenden und nachfolgenden Leerzeichen); die leere Zeichenkette wird in 0 umgewandelt. Beispiel: |
Ein Objekt | Aufruf von |
Bei der Konvertierung der leeren Zeichenkette in eine Zahl wäre NaN arguably das bessere Ergebnis. Das Ergebnis 0 wurde gewählt, um bei leeren numerischen Eingabefeldern zu helfen, im Einklang damit, was andere Programmiersprachen Mitte der 1990er Jahre taten.[14]
Die beiden gebräuchlichsten Arten, einen beliebigen Wert in eine Zahl umzuwandeln, sind:
| (Als Funktion aufgerufen, nicht als Konstruktor) |
|
Ich bevorzuge Number(), da es aussagekräftiger ist. Hier sind einige Beispiele
> Number('')
0
> Number('123')
123
> Number('\t\v\r12.34\n ') // ignores leading and trailing whitespace
12.34
> Number(false)
0
> Number(true)
1parseFloat(str)
konvertiert str in eine Zeichenkette, entfernt führende Leerzeichen und parst dann das längste Präfix, das eine Fließkommazahl ist. Wenn kein solches Präfix existiert (z. B. in einer leeren Zeichenkette), wird NaN zurückgegeben.
Vergleich von parseFloat() und Number()
Die Anwendung von parseFloat() auf eine Nicht-Zeichenkette ist weniger effizient, da sie ihr Argument vor dem Parsen in eine Zeichenkette umwandelt. Infolgedessen werden viele Werte, die Number() in tatsächliche Zahlen umwandelt, von parseFloat() in NaN umgewandelt.
> parseFloat(true) // same as parseFloat('true')
NaN
> Number(true)
1
> parseFloat(null) // same as parseFloat('null')
NaN
> Number(null)
0
parseFloat() parst die leere Zeichenkette als NaN
> parseFloat('')
NaN
> Number('')
0
parseFloat() parst bis zum letzten gültigen Zeichen, was bedeutet, dass Sie ein Ergebnis erhalten, wo Sie es vielleicht nicht wollen.
> parseFloat('123.45#')
123.45
> Number('123.45#')
NaN
parseFloat() ignoriert führende Leerzeichen und stoppt vor ungültigen Zeichen (einschließlich Leerzeichen).
> parseFloat('\t\v\r12.34\n ')
12.34Number() ignoriert sowohl führende als auch nachfolgende Leerzeichen (aber andere ungültige Zeichen führen zu NaN).
JavaScript hat mehrere spezielle Zahlenwerte:
NaN und Infinity.+0 und -0. JavaScript hat zwei Nullen, eine positive Null und eine negative Null, da das Vorzeichen und der Betrag einer Zahl getrennt gespeichert werden. In den meisten Teilen dieses Buches tue ich so, als gäbe es nur eine einzige Null, und Sie werden in JavaScript fast nie sehen, dass es zwei davon gibt.Der Fehlerwert NaN (eine Abkürzung für „not a number“) ist ironischerweise ein Zahlenwert:
> typeof NaN 'number'
Er wird durch Fehler wie die folgenden erzeugt
Eine Zahl konnte nicht geparst werden
> Number('xyz')
NaN
> Number(undefined)
NaNEine Operation ist fehlgeschlagen
> Math.acos(2) NaN > Math.log(-1) NaN > Math.sqrt(-1) NaN
Einer der Operanden ist NaN (dies stellt sicher, dass Sie bei einem Fehler während einer längeren Berechnung ihn im Endergebnis sehen können)
> NaN + 3 NaN > 25 / NaN NaN
NaN ist der einzige Wert, der nicht gleich sich selbst ist:
> NaN === NaN false
Strikte Gleichheit (===) wird auch von Array.prototype.indexOf verwendet. Sie können daher NaN mit dieser Methode nicht in einem Array suchen.
> [ NaN ].indexOf(NaN) -1
Wenn Sie prüfen möchten, ob ein Wert NaN ist, müssen Sie die globale Funktion isNaN() verwenden:
> isNaN(NaN) true > isNaN(33) false
Allerdings funktioniert isNaN nicht richtig mit Nicht-Zahlen, da es diese zuerst in Zahlen umwandelt. Diese Umwandlung kann NaN ergeben und dann gibt die Funktion fälschlicherweise true zurück.
> isNaN('xyz')
trueDaher ist es am besten, isNaN mit einer Typüberprüfung zu kombinieren:
functionmyIsNaN(value){returntypeofvalue==='number'&&isNaN(value);}
Alternativ können Sie prüfen, ob der Wert ungleich sich selbst ist (da NaN der einzige Wert mit diesem Merkmal ist). Aber das ist weniger selbsterklärend:
functionmyIsNaN(value){returnvalue!==value;}
Beachten Sie, dass dieses Verhalten durch IEEE 754 diktiert wird. Wie in Abschnitt 7.11, „Details von Vergleichsprädikaten“ erwähnt:[15]
Jedes NaN soll ungeordnet mit allem, einschließlich sich selbst, verglichen werden.
Infinity ist ein Fehlerwert, der eines von zwei Problemen anzeigt: eine Zahl kann nicht dargestellt werden, weil ihr Betrag zu groß ist, oder eine Division durch Null ist erfolgt.
Infinity ist größer als jede andere Zahl (außer NaN). Ebenso ist -Infinity kleiner als jede andere Zahl (außer NaN). Das macht sie nützlich als Standardwerte – zum Beispiel, wenn Sie nach einem Minimum oder Maximum suchen.
Wie groß der Betrag einer Zahl sein kann, wird durch ihre interne Darstellung bestimmt (wie in Die interne Darstellung von Zahlen diskutiert), die das arithmetische Produkt von ist
Der Exponent muss zwischen −1023 und 1024 (ausschließlich) liegen. Wenn der Exponent zu klein ist, wird die Zahl 0. Wenn der Exponent zu groß ist, wird sie Infinity. 21023 kann noch dargestellt werden, aber 21024 nicht.
> Math.pow(2, 1023) 8.98846567431158e+307 > Math.pow(2, 1024) Infinity
Die Division durch Null ergibt Infinity als Fehlerwert:
> 3 / 0 Infinity > 3 / -0 -Infinity
Sie erhalten das Fehlerergebnis NaN, wenn Sie versuchen, eine Infinity mit einer anderen zu „neutralisieren“:
> Infinity - Infinity NaN > Infinity / Infinity NaN
Wenn Sie versuchen, über Infinity hinauszugehen, erhalten Sie immer noch Infinity.
> Infinity + Infinity Infinity > Infinity * Infinity Infinity
Strikte und tolerante Gleichheit funktionieren für Infinity einwandfrei:
> var x = Infinity; > x === Infinity true
Zusätzlich erlaubt die globale Funktion isFinite() Ihnen zu überprüfen, ob ein Wert eine tatsächliche Zahl ist (weder unendlich noch NaN):
> isFinite(5) true > isFinite(Infinity) false > isFinite(NaN) false
Da die Zahlen von JavaScript Betrag und Vorzeichen getrennt halten, hat jede nicht-negative Zahl ein negatives Gegenstück, einschließlich 0.
Der Grund dafür ist, dass bei der digitalen Darstellung einer Zahl diese so klein werden kann, dass sie von 0 nicht zu unterscheiden ist, da die Kodierung nicht präzise genug ist, um den Unterschied darzustellen. Dann erlaubt ein vorzeichenbehaftetes Null die Aufzeichnung „aus welcher Richtung“ man sich Null genähert hat; das heißt, welches Vorzeichen die Zahl hatte, bevor sie als Null betrachtet wurde. Wikipedia fasst die Vor- und Nachteile von vorzeichenbehafteten Nullen schön zusammen.
Es wird behauptet, dass die Aufnahme von vorzeichenbehaftetem Null in IEEE 754 die numerische Genauigkeit bei einigen kritischen Problemen, insbesondere bei Berechnungen mit komplexen elementaren Funktionen, erheblich erleichtert. Auf der anderen Seite widerspricht das Konzept der vorzeichenbehafteten Null der allgemeinen Annahme in den meisten mathematischen Bereichen (und in den meisten mathematischen Kursen), dass negative Null dasselbe ist wie Null. Darstellungen, die negative Null zulassen, können eine Fehlerquelle in Programmen sein, da Softwareentwickler nicht erkennen (oder vergessen), dass die beiden Null-Darstellungen zwar bei numerischen Vergleichen gleich funktionieren, aber unterschiedliche Bitmuster sind und in einigen Operationen unterschiedliche Ergebnisse liefern.
JavaScript tut viel, um zu verbergen, dass es zwei Nullen gibt. Da es normalerweise keine Rolle spielt, dass sie unterschiedlich sind, wird empfohlen, dass Sie sich der Illusion der einzelnen Null anschließen. Untersuchen wir, wie diese Illusion aufrechterhalten wird.
In JavaScript schreiben Sie normalerweise 0, was +0 bedeutet. Aber -0 wird auch einfach als 0 angezeigt. Das sehen Sie, wenn Sie eine Browser-Befehlszeile oder die Node.js REPL verwenden.
> -0 0
Das liegt daran, dass die Standardmethode toString() beide Nullen in dieselbe '0' umwandelt:
> (-0).toString() '0' > (+0).toString() '0'
Gleichheit unterscheidet Nullen ebenfalls nicht. Nicht einmal ===:
> +0 === -0 true
Array.prototype.indexOf verwendet ===, um nach Elementen zu suchen, und wahrt so die Illusion.
> [ -0, +0 ].indexOf(+0) 0 > [ +0, -0 ].indexOf(-0) 0
Die Ordnungsoperatoren betrachten die Nullen ebenfalls als gleich.
> -0 < +0 false > +0 < -0 false
Wie kann man tatsächlich beobachten, dass die beiden Nullen unterschiedlich sind? Man kann durch Null teilen (-Infinity und +Infinity können durch === unterschieden werden):
> 3 / -0 -Infinity > 3 / +0 Infinity
Eine weitere Möglichkeit, die Division durch Null durchzuführen, ist über Math.pow() (siehe Numerische Funktionen)
> Math.pow(-0, -1) -Infinity > Math.pow(+0, -1) Infinity
Math.atan2() (siehe Trigonometrische Funktionen) enthüllt ebenfalls, dass die Nullen unterschiedlich sind:
> Math.atan2(-0, -1) -3.141592653589793 > Math.atan2(+0, -1) 3.141592653589793
Die kanonische Methode zur Unterscheidung der beiden Nullen ist die Division durch Null. Daher würde eine Funktion zur Erkennung negativer Nullen wie folgt aussehen:
functionisNegativeZero(x){returnx===0&&(1/x<0);}
Hier ist die Funktion in Aktion.
> isNegativeZero(0) false > isNegativeZero(-0) true > isNegativeZero(33) false
JavaScript-Zahlen haben eine 64-Bit-Präzision, die auch als doppelte Präzision bezeichnet wird (Typ double in einigen Programmiersprachen). Die interne Darstellung basiert auf dem IEEE-754-Standard. Die 64 Bits werden auf Vorzeichen, Exponenten und Bruchteil einer Zahl wie folgt verteilt:
| Vorzeichen | Exponent ∈ [−1023, 1024] | Bruchteil |
1 Bit | 11 Bits | 52 Bits |
Bit 63 | Bits 62–52 | Bits 51–0 |
Der Wert einer Zahl wird mit der folgenden Formel berechnet
(–1)sign × %1.fraction × 2exponent
Das vorangestellte Prozentzeichen (%) bedeutet, dass die Zahl in der Mitte in Binärdarstellung geschrieben ist: eine 1, gefolgt von einem Binärpunkt, gefolgt von einem Binärbruch – nämlich den Binärziffern des Bruchteils (eine natürliche Zahl). Hier sind einige Beispiele dieser Darstellung:
+0 | (Vorzeichen = 0, Bruchteil = 0, Exponent = −1023) | |
–0 | (Vorzeichen = 1, Bruchteil = 0, Exponent = −1023) | |
1 | = (−1)0 × %1.0 × 20 | (Vorzeichen = 0, Bruchteil = 0, Exponent = 0) |
2 | = (−1)0 × %1.0 × 21 | |
3 | = (−1)0 × %1.1 × 21 | (Vorzeichen = 0, Bruchteil = 251, Exponent = 0) |
0.5 | = (−1)0 × %1.0 × 2−1 | |
−1 | = (−1)1 × %1.0 × 20 |
Die Kodierungen von +0, −0 und 3 lassen sich wie folgt erklären:
Die zuvor erwähnte Darstellung von Zahlen wird als normalisiert bezeichnet. In diesem Fall liegt der Exponent e im Bereich −1023 < e < 1024 (untere und obere Grenzen ausgeschlossen). −1023 und 1024 sind spezielle Exponenten:
NaN und Infinity verwendet.−1023 wird verwendet für
Um beide Anwendungen zu ermöglichen, wird eine andere, sogenannte denormalisierte, Darstellung verwendet:
(–1)sign × %0.fraction × 2–1022
Zum Vergleich sind die kleinsten (im Sinne von „am nächsten bei Null“) Zahlen in normalisierter Darstellung:
(–1)sign × %1.fraction × 2–1022
Denormalisierte Zahlen sind kleiner, da es keine führende Ziffer 1 gibt.
JavaScript-Zahlen werden normalerweise als dezimale Fließkommazahlen eingegeben, sind aber intern als binäre Fließkommazahlen dargestellt. Dies führt zu Ungenauigkeit. Um zu verstehen, warum, vergessen wir das interne Speicherformat von JavaScript und betrachten allgemein, welche Brüche gut durch dezimale Fließkommazahlen und welche durch binäre Fließkommazahlen dargestellt werden können. Im Dezimalsystem sind alle Brüche ein Mantisse m geteilt durch eine Potenz von 10:

Es gibt also im Nenner nur Zehnen. Deshalb kann
nicht exakt als dezimale Fließkommazahl ausgedrückt werden – es gibt keine Möglichkeit, eine 3 in den Nenner zu bekommen. Binäre Fließkommazahlen haben nur Zweien im Nenner. Untersuchen wir, welche dezimalen Fließkommazahlen gut als binär und welche nicht dargestellt werden können. Wenn es nur Zweien im Nenner gibt, kann die Dezimalzahl dargestellt werden.
Andere Brüche können nicht exakt dargestellt werden, da sie Zahlen außer 2 im Nenner haben (nach Primfaktorzerlegung).

Man sieht normalerweise nicht, dass JavaScript intern nicht exakt 0.1 speichert. Aber man kann es sichtbar machen, indem man es mit einer ausreichend hohen Potenz von 10 multipliziert.
> 0.1 * Math.pow(10, 24) 1.0000000000000001e+23
Und wenn Sie zwei ungenau dargestellte Zahlen addieren, ist das Ergebnis manchmal ungenau genug, dass die Ungenauigkeit sichtbar wird.
> 0.1 + 0.2 0.30000000000000004
Ein weiteres Beispiel
> 0.1 + 1 - 1 0.10000000000000009
Aufgrund von Rundungsfehlern sollten Sie als beste Praxis keine nicht-ganzen Zahlen direkt vergleichen. Berücksichtigen Sie stattdessen eine Obergrenze für Rundungsfehler. Eine solche Obergrenze wird als Maschinen-Epsilon bezeichnet. Der Standardwert für doppelte Präzision ist 2−53:
varEPSILON=Math.pow(2,-53);functionepsEqu(x,y){returnMath.abs(x-y)<EPSILON;}
epsEqu() stellt korrekte Ergebnisse sicher, wo ein normaler Vergleich unzureichend wäre.
> 0.1 + 0.2 === 0.3 false > epsEqu(0.1+0.2, 0.3) true
Wie bereits erwähnt, gibt es in JavaScript nur Fließkommazahlen. Ganze Zahlen erscheinen intern auf zwei Arten. Erstens speichert die meisten JavaScript-Engines eine ausreichend kleine Zahl ohne Dezimalbruch als ganze Zahl (mit z. B. 31 Bits) und behält diese Darstellung so lange wie möglich bei. Sie müssen auf eine Fließkommadarstellung zurückschalten, wenn der Betrag einer Zahl zu groß wird oder ein Dezimalbruch auftritt.
Zweitens hat die ECMAScript-Spezifikation Ganzzahloperatoren: nämlich alle bitweisen Operatoren. Diese Operatoren konvertieren ihre Operanden in 32-Bit-Integer und geben 32-Bit-Integer zurück. Für die Spezifikation bedeutet Integer nur, dass die Zahlen keinen Dezimalbruch haben, und 32-Bit bedeutet, dass sie sich innerhalb eines bestimmten Bereichs befinden. Für Engines bedeutet 32-Bit-Integer, dass eine tatsächliche Ganzzahl- (Nicht-Fließkomma-) Darstellung normalerweise eingeführt oder beibehalten werden kann.
Intern sind die folgenden Bereiche von ganzen Zahlen in JavaScript wichtig:
Sichere ganze Zahlen (sieheSichere ganze Zahlen), der größte praktisch nutzbare Bereich von ganzen Zahlen, den JavaScript unterstützt.
Array-Indizes (sieheArray-Indizes)
Bitweise Operanden (sieheBitweise Operatoren)
>>>): 32 Bits, vorzeichenlos, Bereich [0, 232)„Char-Codes“, UTF-16-Codeeinheiten als Zahlen
String.fromCharCode() (sieheString-Konstruktor-Methode)String.prototype.charCodeAt() (sieheTeilstrings extrahieren)JavaScript kann nur Ganzzahlwerte bis zu einem Betrag von 53 Bits handhaben (die 52 Bits des Bruchteils plus 1 indirektes Bit, über den Exponenten; siehe Die interne Darstellung von Zahlen für Details).
Die folgende Tabelle erklärt, wie JavaScript 53-Bit-Ganzzahlen als Fließkommazahlen darstellt.
| Bits | Bereich | Kodierung |
1 Bit | 0 | |
1 Bit | 1 | %1 × 20 |
2 Bits | 2–3 | %1.f51 × 21 |
3 Bits | 4–7 = 22–(23−1) | %1.f51f50 × 22 |
4 Bits | 23–(24−1) | %1.f51f50f49 × 23 |
⋯ | ⋯ | ⋯ |
53 Bits | 252–(253−1) | %1.f51⋯f0 × 252 |
Es gibt keine feste Bitfolge, die die ganze Zahl darstellt. Stattdessen wird die Mantisse %1.f durch den Exponenten verschoben, so dass die führende Ziffer 1 an der richtigen Stelle steht. In gewisser Weise zählt der Exponent die Anzahl der Bruchteile, die aktiv genutzt werden (die verbleibenden Ziffern sind 0). Das bedeutet, dass wir für 2 Bits eine Ziffer des Bruchteils verwenden und für 53 Bits alle Ziffern des Bruchteils verwenden. Zusätzlich können wir 253 als %1.0 × 253 darstellen, aber bei höheren Zahlen bekommen wir Probleme.
| Bits | Bereich | Kodierung |
54 Bits | 253–(254−1) | %1.f51⋯f00 × 253 |
55 Bits | 254–(255−1) | %1.f51⋯f000 × 254 |
⋯ |
Bei 54 Bits ist die niederwertigste Ziffer immer 0, bei 55 Bits sind die beiden niederwertigsten Ziffern immer 0, und so weiter. Das bedeutet, dass wir bei 54 Bits nur jede zweite Zahl darstellen können, bei 55 Bits nur jede vierte Zahl, und so weiter. Zum Beispiel:
> Math.pow(2, 53) - 1 // OK 9007199254740991 > Math.pow(2, 53) // OK 9007199254740992 > Math.pow(2, 53) + 1 // can't be represented 9007199254740992 > Math.pow(2, 53) + 2 // OK 9007199254740994
Wenn Sie mit ganzen Zahlen bis zu einem Betrag von 53 Bits arbeiten, sind Sie auf der sicheren Seite. Leider stoßen Sie in der Programmierung oft auf 64-Bit-Ganzzahlen ohne Vorzeichen (Twitter-IDs, Datenbanken usw.). Diese müssen in JavaScript in Zeichenketten gespeichert werden. Wenn Sie Berechnungen mit solchen ganzen Zahlen durchführen möchten, benötigen Sie spezielle Bibliotheken. Es gibt Pläne, größere ganze Zahlen in JavaScript einzuführen, aber das wird noch eine Weile dauern.
JavaScript kann Ganzzahlen i nur im Bereich −253 < i < 253 sicher darstellen. Dieser Abschnitt untersucht, was das bedeutet und welche Folgen es hat. Er basiert auf einer E-Mail von Mark S. Miller an die es-discuss Mailingliste.
Die Idee einer sicheren Ganzzahl konzentriert sich darauf, wie mathematische Ganzzahlen in JavaScript dargestellt werden. Im Bereich (−253, 253) (untere und obere Grenzen ausgeschlossen) sind JavaScript-Ganzzahlen sicher: es gibt eine Eins-zu-eins-Zuordnung zwischen mathematischen Ganzzahlen und ihren Darstellungen in JavaScript.
Außerhalb dieses Bereichs sind JavaScript-Ganzzahlen unsicher: zwei oder mehr mathematische Ganzzahlen werden als dieselbe JavaScript-Ganzzahl dargestellt. Zum Beispiel kann JavaScript ab 253 nur jede zweite mathematische Ganzzahl darstellen (der vorherige Abschnitt erklärt, warum). Daher ist eine sichere JavaScript-Ganzzahl eine, die eindeutig eine einzelne mathematische Ganzzahl darstellt.
ECMAScript 6 wird die folgenden Konstanten bereitstellen:
Number.MAX_SAFE_INTEGER=Math.pow(2,53)-1;Number.MIN_SAFE_INTEGER=-Number.MAX_SAFE_INTEGER;
Es wird auch eine Funktion bereitstellen, um festzustellen, ob eine Ganzzahl sicher ist:
Number.isSafeInteger=function(n){return(typeofn==='number'&&Math.round(n)===n&&Number.MIN_SAFE_INTEGER<=n&&n<=Number.MAX_SAFE_INTEGER);}
Für einen gegebenen Wert n prüft diese Funktion zuerst, ob n eine Zahl und eine ganze Zahl ist. Wenn beide Prüfungen erfolgreich sind, ist n sicher, wenn es größer oder gleich MIN_SAFE_INTEGER und kleiner oder gleich MAX_SAFE_INTEGER ist.
Wie können wir sicherstellen, dass Ergebnisse von arithmetischen Berechnungen korrekt sind? Zum Beispiel ist das folgende Ergebnis eindeutig nicht korrekt:
> 9007199254740990 + 3 9007199254740992
Wir haben zwei sichere Operanden, aber ein unsicheres Ergebnis.
> Number.isSafeInteger(9007199254740990) true > Number.isSafeInteger(3) true > Number.isSafeInteger(9007199254740992) false
Das folgende Ergebnis ist ebenfalls falsch.
> 9007199254740995 - 10 9007199254740986
Diesmal ist das Ergebnis sicher, aber einer der Operanden ist es nicht.
> Number.isSafeInteger(9007199254740995) false > Number.isSafeInteger(10) true > Number.isSafeInteger(9007199254740986) true
Daher ist das Ergebnis der Anwendung eines Ganzzahloperators op nur dann garantiert korrekt, wenn alle Operanden und das Ergebnis sicher sind. Formaler:
isSafeInteger(a) && isSafeInteger(b) && isSafeInteger(a op b)
impliziert, dass a op b ein korrektes Ergebnis ist.
In JavaScript sind alle Zahlen Fließkommazahlen. Ganze Zahlen sind Fließkommazahlen ohne Bruch. Die Konvertierung einer Zahl n in eine ganze Zahl bedeutet, die „nächste“ ganze Zahl zu n zu finden (wobei die Bedeutung von „nächste“ davon abhängt, wie man konvertiert). Sie haben mehrere Optionen, diese Konvertierung durchzuführen:
Math-Funktionen Math.floor(), Math.ceil() und Math.round() (sieheGanze Zahlen über Math.floor(), Math.ceil() und Math.round())ToInteger() (sieheGanze Zahlen über die benutzerdefinierte Funktion ToInteger())parseInt() (sieheGanze Zahlen über parseInt())Spoiler: #1 ist normalerweise die beste Wahl, #2 und #3 haben Nischenanwendungen, und #4 ist zum Parsen von Zeichenketten in Ordnung, aber nicht zum Konvertieren von Zahlen in ganze Zahlen.
Die folgenden drei Funktionen sind normalerweise die beste Methode, um eine Zahl in eine ganze Zahl umzuwandeln.
Math.floor() konvertiert sein Argument in die nächstkleinere ganze Zahl:
> Math.floor(3.8) 3 > Math.floor(-3.8) -4
Math.ceil() konvertiert sein Argument in die nächstgrößere ganze Zahl:
> Math.ceil(3.2) 4 > Math.ceil(-3.2) -3
Math.round() konvertiert sein Argument in die nächstgelegene ganze Zahl:
> Math.round(3.2) 3 > Math.round(3.5) 4 > Math.round(3.8) 4
Das Ergebnis des Rundens von -3.5 kann überraschend sein.
> Math.round(-3.2) -3 > Math.round(-3.5) -3 > Math.round(-3.8) -4
Daher ist Math.round(x) dasselbe wie
Math.floor(x+0.5)
Eine weitere gute Option, um einen beliebigen Wert in eine ganze Zahl umzuwandeln, ist die interne ECMAScript-Operation ToInteger(), die den Bruch einer Fließkommazahl entfernt. Wenn sie in JavaScript zugänglich wäre, würde sie so funktionieren:
> ToInteger(3.2) 3 > ToInteger(3.5) 3 > ToInteger(3.8) 3 > ToInteger(-3.2) -3 > ToInteger(-3.5) -3 > ToInteger(-3.8) -3
Die ECMAScript-Spezifikation definiert das Ergebnis von ToInteger(number) als
sign(number) × floor(abs(number))
Für das, was sie tut, ist diese Formel relativ kompliziert, da floor die nächstgrößere ganze Zahl sucht; wenn Sie den Bruch einer negativen ganzen Zahl entfernen möchten, müssen Sie die nächstkleinere ganze Zahl suchen. Der folgende Code implementiert die Operation in JavaScript. Wir vermeiden die sign-Operation, indem wir ceil verwenden, wenn die Zahl negativ ist.
functionToInteger(x){x=Number(x);returnx<0?Math.ceil(x):Math.floor(x);}
Bitweise Operatoren (sieheBinäre bitweise Operatoren) konvertieren (mindestens) einen ihrer Operanden in eine 32-Bit-Ganzzahl, die dann manipuliert wird, um ein Ergebnis zu erzeugen, das ebenfalls eine 32-Bit-Ganzzahl ist. Wenn Sie den anderen Operanden entsprechend wählen, erhalten Sie eine schnelle Möglichkeit, eine beliebige Zahl in eine 32-Bit-Ganzzahl (entweder vorzeichenbehaftet oder vorzeichenlos) umzuwandeln.
Wenn die Maske, der zweite Operand, 0 ist, ändern Sie keine Bits und das Ergebnis ist der erste Operand, umgewandelt in eine vorzeichenbehaftete 32-Bit-Ganzzahl. Dies ist die kanonische Methode, diese Art von Umwandlung durchzuführen, und wird z. B. von asm.js verwendet (siehe Ist JavaScript schnell genug?)
// Convert x to a signed 32-bit integerfunctionToInt32(x){returnx|0;}
ToInt32() entfernt den Bruch und wendet Modulo 232 an:
> ToInt32(1.001) 1 > ToInt32(1.999) 1 > ToInt32(1) 1 > ToInt32(-1) -1 > ToInt32(Math.pow(2, 32)+1) 1 > ToInt32(Math.pow(2, 32)-1) -1
Der gleiche Trick, der für bitweises ODER funktionierte, funktioniert auch für Schiebeoperatoren: wenn Sie um null Bits verschieben, ist das Ergebnis einer Schiebeoperation der erste Operand, umgewandelt in eine 32-Bit-Ganzzahl. Hier sind einige Beispiele für die Implementierung von Operationen der ECMAScript-Spezifikation über Schiebeoperatoren:
// Convert x to a signed 32-bit integerfunctionToInt32(x){returnx<<0;}// Convert x to a signed 32-bit integerfunctionToInt32(x){returnx>>0;}// Convert x to an unsigned 32-bit integerfunctionToUint32(x){returnx>>>0;}
Hier ist ToUint32() in Aktion:
> ToUint32(-1) 4294967295 > ToUint32(Math.pow(2, 32)-1) 4294967295 > ToUint32(Math.pow(2, 32)) 0
Sie müssen selbst entscheiden, ob der geringe Effizienzgewinn es wert ist, dass Ihr Code schwerer zu verstehen ist. Beachten Sie auch, dass bitweise Operatoren sich künstlich auf 32 Bits beschränken, was oft weder notwendig noch nützlich ist. Die Verwendung einer der Math-Funktionen, möglicherweise in Verbindung mit Math.abs(), ist eine selbsterklärendere und arguably bessere Wahl.
parseInt(str,radix?)
parst die Zeichenkette str (Nicht-Zeichenketten werden umgewandelt) als ganze Zahl. Die Funktion ignoriert führende Leerzeichen und berücksichtigt so viele aufeinanderfolgende gültige Ziffern, wie sie finden kann.
Der Wertebereich für die Radix ist 2 ≤ radix ≤ 36. Sie bestimmt die Basis der zu parsierenden Zahl. Wenn die Radix größer als 10 ist, werden zusätzlich zu 0–9 Buchstaben als Ziffern verwendet (Groß- und Kleinschreibung wird nicht beachtet).
Wenn radix fehlt, wird angenommen, dass sie 10 ist, es sei denn, str beginnt mit „0x“ oder „0X“, in welchem Fall radix auf 16 (hexadezimal) gesetzt wird.
> parseInt('0xA')
10Wenn radix bereits 16 ist, ist das hexadezimale Präfix optional.
> parseInt('0xA', 16)
10
> parseInt('A', 16)
10Bisher habe ich das Verhalten von parseInt() gemäß der ECMAScript-Spezifikation beschrieben. Zusätzlich setzen einige Engines die Radix auf 8, wenn str mit einer Null beginnt.
> parseInt('010')
8
> parseInt('0109') // ignores digits ≥ 8
8Daher ist es am besten, die Radix immer explizit anzugeben und parseInt() immer mit zwei Argumenten aufzurufen.
Hier sind einige Beispiele.
> parseInt('')
NaN
> parseInt('zz', 36)
1295
> parseInt(' 81', 10)
81
> parseInt('12**', 10)
12
> parseInt('12.34', 10)
12
> parseInt(12.34, 10)
12Verwenden Sie parseInt() nicht, um eine Zahl in einen Integer umzuwandeln. Das letzte Beispiel gibt uns Hoffnung, dass wir parseInt() für die Konvertierung von Zahlen in Integer verwenden können. Leider gibt es hier ein Beispiel, bei dem die Konvertierung falsch ist:
> parseInt(1000000000000000000000.5, 10) 1
Das Argument wird zuerst in einen String konvertiert.
> String(1000000000000000000000.5) '1e+21'
parseInt betrachtet „e“ nicht als Integer-Ziffer und stoppt daher das Parsen nach der 1. Hier ist ein weiteres Beispiel:
> parseInt(0.0000008, 10) 8 > String(0.0000008) '8e-7'
parseInt() sollte nicht verwendet werden, um Zahlen in Integer umzuwandeln: Die Typumwandlung in einen String ist ein unnötiger Umweg und selbst dann ist das Ergebnis nicht immer korrekt.
parseInt() ist nützlich für das Parsen von Strings, aber man muss sich bewusst sein, dass es beim ersten illegalen Zeichen stoppt. Das Parsen von Strings über Number() (siehe Die Funktion Number) ist weniger nachsichtig, kann aber zu Nicht-Integer-Ergebnissen führen.
Die folgenden Operatoren sind für Zahlen verfügbar:
number1 + number2
Numerische Addition, es sei denn, einer der Operanden ist ein String. Dann werden beide Operanden in Strings konvertiert und verkettet (siehe Der Plus-Operator (+))
> 3.1 + 4.3 7.4 > 4 + ' messages' '4 messages'
number1 - number2
number1 * number2
number1 / number2
number1 % number2
Rest
> 9 % 7 2 > -9 % 7 -2
Diese Operation ist keine Modulo-Operation. Sie gibt einen Wert zurück, dessen Vorzeichen mit dem des ersten Operanden übereinstimmt (mehr dazu gleich).
-number
+number
++variable, --variableGibt den aktuellen Wert der Variablen zurück, nachdem sie um 1 erhöht (oder verringert) wurde:
> var x = 3; > ++x 4 > x 4
variable++, variable--Erhöht (oder verringert) den Wert der Variablen um 1 und gibt ihn zurück.
> var x = 3; > x++ 3 > x 4
Die Position des Operanden kann Ihnen helfen zu erinnern, ob er vor oder nach der Erhöhung (oder Verringerung) zurückgegeben wird. Wenn der Operand vor dem Inkrement-Operator steht, wird er vor der Erhöhung zurückgegeben. Wenn der Operand nach dem Operator steht, wird er erhöht und dann zurückgegeben. (Der Dekrement-Operator funktioniert ähnlich.)
JavaScript hat mehrere bitweise Operatoren, die mit 32-Bit-Integern arbeiten. Das heißt, sie konvertieren ihre Operanden in 32-Bit-Integer und produzieren ein Ergebnis, das ein 32-Bit-Integer ist. Anwendungsfälle für diese Operatoren sind die Verarbeitung binärer Protokolle, spezielle Algorithmen usw.
Dieser Abschnitt erklärt einige Konzepte, die Ihnen helfen werden, bitweise Operatoren zu verstehen.
Zwei gängige Methoden zur Berechnung eines binären Komplements (oder Inversen) einer Binärzahl sind:
Sie berechnen das Einerkomplement ~x einer Zahl x, indem Sie jede der 32 Ziffern invertieren. Wir veranschaulichen das Einerkomplement anhand von vierstelligen Zahlen. Das Einerkomplement von 1100 ist 0011. Wenn Sie eine Zahl zu ihrem Einerkomplement addieren, erhalten Sie eine Zahl, deren Ziffern alle 1 sind.
1 + ~1 = 0001 + 1110 = 1111
1 + -1 = 0001 + 1111 = 0000
32-Bit-Integer haben kein explizites Vorzeichen, aber Sie können trotzdem negative Zahlen kodieren. Zum Beispiel kann −1 als Zweierkomplement von 1 kodiert werden: Wenn Sie 1 zum Ergebnis addieren, erhalten Sie 0 (innerhalb von 32 Bit). Die Grenze zwischen positiven und negativen Zahlen ist fließend; 4294967295 (232−1) und −1 sind hier derselbe Integer. Sie müssen sich jedoch für ein Vorzeichen entscheiden, wenn Sie einen solchen Integer von oder zu einer JavaScript-Zahl konvertieren, die ein explizites Vorzeichen hat, im Gegensatz zu einem impliziten. Daher sind vorzeichenbehaftete 32-Bit-Integer in zwei Gruppen unterteilt:
Das höchstwertige Bit wird oft als Vorzeichenbit bezeichnet. Entsprechend wird 4294967295, interpretiert als vorzeichenbehafteter 32-Bit-Integer, zu −1, wenn es in eine JavaScript-Zahl konvertiert wird.
> ToInt32(4294967295) -1
ToInt32() wird in 32-Bit-Integer über Bitwise-Operatoren erläutert.
Nur der vorzeichenlose Rechtsverschiebeoperator (>>>) arbeitet mit vorzeichenlosen 32-Bit-Integern; alle anderen bitweisen Operatoren arbeiten mit vorzeichenbehafteten 32-Bit-Integern.
In den folgenden Beispielen arbeiten wir mit binären Zahlen über die folgenden beiden Operationen:
parseInt(str, 2) (siehe Integer über parseInt()) parst einen String str in binärer Notation (Basis 2). Zum Beispiel:
> parseInt('110', 2)
6
num.toString(2) (siehe Number.prototype.toString(radix?)) konvertiert die Zahl num in eine Zeichenkette in binärer Notation. Zum Beispiel:
> 6..toString(2) '110'
~number berechnet das Einerkomplement von number:
> (~parseInt('11111111111111111111111111111111', 2)).toString(2)
'0'JavaScript hat drei binäre bitweise Operatoren:
number1 & number2 (bitwise And):
> (parseInt('11001010', 2) & parseInt('1111', 2)).toString(2)
'1010'
number1 | number2 (bitwise Or):
> (parseInt('11001010', 2) | parseInt('1111', 2)).toString(2)
'11001111'
number1 ^ number2 (bitwise Xor; eXclusive Or)
> (parseInt('11001010', 2) ^ parseInt('1111', 2)).toString(2)
'11000101'Es gibt zwei Möglichkeiten, binäre bitweise Operatoren intuitiv zu verstehen:
In den folgenden Formeln bedeutet ni Bit i von Zahl n, interpretiert als boolescher Wert (0 ist false, 1 ist true). Zum Beispiel ist 20 false; 21 ist true.
resulti = number1i && number2i resulti = number1i || number2i Xor: resulti = number1i ^^ number2i
Der Operator ^^ existiert nicht. Wenn er existieren würde, würde er so funktionieren (das Ergebnis ist true, wenn genau einer der Operanden true ist).
x^^y===(x&&!y)||(!x&&y)
number1 über number2number1, die in number2 gesetzt sind. Diese Operation wird auch als Maskierung bezeichnet, wobei number2 die Maske ist.number1, die in number2 gesetzt sind, und behält alle anderen Bits unverändert.number1, die in number2 gesetzt sind, und behält alle anderen Bits unverändert.JavaScript hat drei bitweise Verschiebeoperatoren:
number << digitCount (links verschieben):
> (parseInt('1', 2) << 1).toString(2)
'10'
number >> digitCount (vorzeichenbehaftete Rechtsverschiebung):
Die 32-Bit-Binärzahl wird als vorzeichenbehaftet interpretiert (siehe vorheriger Abschnitt). Beim Rechtsverschieben wird das Vorzeichen beibehalten.
> (parseInt('11111111111111111111111111111110', 2) >> 1).toString(2)
'-1'Wir haben –2 nach rechts verschoben. Das Ergebnis, –1, ist äquivalent zu einem 32-Bit-Integer, dessen Ziffern alle 1 sind (das Zweierkomplement von 1). Mit anderen Worten, eine vorzeichenbehaftete Rechtsverschiebung um eine Stelle teilt sowohl negative als auch positive Integer durch zwei.
number >>> digitCount` (vorzeichenlose Rechtsverschiebung)
> (parseInt('11100', 2) >>> 1).toString(2)
'1110'Wie Sie sehen können, verschiebt dieser Operator von links Nullen ein.
Die Funktion Number kann auf zwei Arten aufgerufen werden:
Number(value)
Als normale Funktion konvertiert sie value in eine primitive Zahl (siehe Konvertierung in Number).
> Number('123')
123
> typeof Number(3) // no change
'number'new Number(num)
Als Konstruktor erstellt sie eine neue Instanz von Number (siehe Wrapper-Objekte für Primitives), ein Objekt, das num umschließt (nachdem es in eine Zahl konvertiert wurde). Zum Beispiel:
> typeof new Number(3) 'object'
Der erstere Aufruf ist der gebräuchlichste.
Das Objekt Number hat die folgenden Eigenschaften:
Number.MAX_VALUE
Die größte darstellbare positive Zahl. Intern sind alle Ziffern ihrer Bruchteile eins und der Exponent ist maximal, nämlich 1023. Wenn Sie versuchen, den Exponenten durch Multiplikation mit zwei zu erhöhen, ist das Ergebnis der Fehlerwert Infinity (siehe Infinity)
> Number.MAX_VALUE 1.7976931348623157e+308 > Number.MAX_VALUE * 2 Infinity
Number.MIN_VALUE
Die kleinste darstellbare positive Zahl (größer als Null, ein winziger Bruch):
> Number.MIN_VALUE 5e-324
Number.NaN
NaN.Number.NEGATIVE_INFINITY
Derselbe Wert wie -Infinity:
> Number.NEGATIVE_INFINITY === -Infinity true
Number.POSITIVE_INFINITY
Derselbe Wert wie Infinity:
> Number.POSITIVE_INFINITY === Infinity true
Alle Methoden von primitiven Zahlen sind in Number.prototype gespeichert (siehe Primitives leihen sich ihre Methoden von Wrappern).
Number.prototype.toFixed(fractionDigits?) gibt eine exponen-freie Darstellung der Zahl zurück, gerundet auf fractionDigits Stellen. Wenn der Parameter weggelassen wird, wird der Wert 0 verwendet:
> 0.0000003.toFixed(10) '0.0000003000' > 0.0000003.toString() '3e-7'
Wenn die Zahl größer oder gleich 1021 ist, dann funktioniert diese Methode genauso wie toString(). Sie erhalten eine Zahl in exponentieller Notation.
> 1234567890123456789012..toFixed() '1.2345678901234568e+21' > 1234567890123456789012..toString() '1.2345678901234568e+21'
Number.prototype.toPrecision(precision?) kürzt die Mantisse auf precision Ziffern, bevor ein Konvertierungsalgorithmus ähnlich wie toString() verwendet wird. Wenn keine Präzision angegeben ist, wird toString() direkt verwendet:
> 1234..toPrecision(3) '1.23e+3' > 1234..toPrecision(4) '1234' > 1234..toPrecision(5) '1234.0' > 1.234.toPrecision(3) '1.23'
Sie benötigen die Exponentialnotation, um 1234 mit einer Präzision von drei Stellen anzuzeigen.
Für Number.prototype.toString(radix?) gibt der Parameter radix die Basis des Systems an, in dem die Zahl angezeigt werden soll. Die gängigsten Radices sind 10 (dezimal), 2 (binär) und 16 (hexadezimal):
> 15..toString(2) '1111' > 65535..toString(16) 'ffff'
Die Radix muss mindestens 2 und höchstens 36 sein. Jede Radix größer als 10 führt zur Verwendung von alphabetischen Zeichen als Ziffern, was das Maximum von 36 erklärt, da das lateinische Alphabet 26 Zeichen hat:
> 1234567890..toString(36) 'kf12oi'
Die globale Funktion parseInt (siehe Integer über parseInt()) ermöglicht es Ihnen, solche Notationen zurück in eine Zahl zu konvertieren:
> parseInt('kf12oi', 36)
1234567890Für die Radix 10 verwendet toString() in zwei Fällen eine Exponentialnotation (mit einer einzelnen Ziffer vor dem Dezimalpunkt). Erstens, wenn mehr als 21 Ziffern vor dem Dezimalpunkt einer Zahl vorhanden sind.
> 1234567890123456789012 1.2345678901234568e+21 > 123456789012345678901 123456789012345680000
Zweitens, wenn eine Zahl mit 0. beginnt, gefolgt von mehr als fünf Nullen und einer Nicht-Null-Ziffer.
> 0.0000003 3e-7 > 0.000003 0.000003
In allen anderen Fällen wird eine feste Notation verwendet.
Number.prototype.toExponential(fractionDigits?) erzwingt die Ausdrucksweise einer Zahl in Exponentialnotation. fractionDigits ist eine Zahl zwischen 0 und 20, die bestimmt, wie viele Ziffern nach dem Dezimalpunkt angezeigt werden sollen. Wenn sie weggelassen wird, werden so viele signifikante Ziffern wie nötig verwendet, um die Zahl eindeutig zu spezifizieren.
In diesem Beispiel erzwingen wir mehr Präzision, wenn toString() ebenfalls die Exponentialnotation verwenden würde. Die Ergebnisse sind gemischt, da wir die Grenzen der Präzision erreichen, die bei der Konvertierung von Binärzahlen in eine Dezimalnotation erzielt werden kann.
> 1234567890123456789012..toString() '1.2345678901234568e+21' > 1234567890123456789012..toExponential(20) '1.23456789012345677414e+21'
In diesem Beispiel ist die Größenordnung der Zahl nicht groß genug für einen Exponenten, der von toString() angezeigt wird. toExponential() zeigt jedoch einen Exponenten an.
> 1234..toString() '1234' > 1234..toExponential(5) '1.23400e+3' > 1234..toExponential() '1.234e+3'
In diesem Beispiel erhalten wir Exponentialnotation, wenn der Bruch nicht klein genug ist.
> 0.003.toString() '0.003' > 0.003.toExponential(4) '3.0000e-3' > 0.003.toExponential() '3e-3'
Die folgenden Funktionen arbeiten mit Zahlen:
isFinite(number)
number eine tatsächliche Zahl ist (weder Infinity noch NaN). Details finden Sie unter Prüfung auf Infinity.isNaN(number)
true zurück, wenn number NaN ist. Details finden Sie unter Fallstrick: Prüfung, ob ein Wert NaN ist.parseFloat(str)
str in eine Fließkommazahl um. Details finden Sie unter parseFloat().parseInt(str, radix?)
str als Integer, dessen Basis radix (2–36) ist. Details finden Sie unter Integer über parseInt().Ich habe die folgenden Quellen bei der Erstellung dieses Kapitels herangezogen:
[14] Quelle: Brendan Eich, http://bit.ly/1lKzQeC.
[15] Béla Varga (@netzzwerg) wies darauf hin, dass IEEE 754 NaN als ungleich sich selbst spezifiziert.