In het moderne JavaScript zijn er twee soorten getallen:
- 
Reguliere getallen in JavaScript worden opgeslagen in het 64-bits formaat IEEE-754, ook wel bekend als “double precision floating point numbers”. Dit zijn de getallen die we het meest gebruiken, en we zullen het er in dit hoofdstuk over hebben. 
- 
BigInt getallen, om gehele getallen van willekeurige lengte weer te geven. Ze zijn soms nodig, omdat een gewoon getal niet groter kan zijn dan 253of kleiner dan-253. Omdat bigints op enkele speciale gebieden worden gebruikt, wijden we ze aan een speciaal hoofdstuk BigInt.
Dus hier gaan we het hebben over reguliere getallen. Laten we onze kennis ervan uitbreiden.
Meer manieren om een getal te schrijven
Stel je voor dat we 1 miljard moeten schrijven. De voor de hand liggende manier is:
let billion = 1000000000;We kunnen ook underscore _ als scheidingsteken gebruiken:
let billion = 1_000_000_000;Hier speelt de underscore_de rol van de “syntactische suiker”, het maakt het getal leesbaarder. De JavaScript engine negeert gewoon_tussen de cijfers, dus het is precies hetzelfde miljard als hierboven.
In het echte leven proberen we echter te vermijden lange reeksen nullen te schrijven. Daar zijn we te lui voor. We zullen proberen iets te schrijven als "1bn" voor een miljard of "7.3bn" voor 7 miljard 300 miljoen. Hetzelfde geldt voor de meeste grote getallen.
In JavaScript kunnen we een getal inkorten door er de letter "e" aan toe te voegen en het aantal nullen op te geven:
let billion = 1e9; // 1 billion, literally: 1 and 9 zeroesalert( 7.3e9 ); // 7.3 billions (same as 7300000000 or 7_300_000_000)In andere woorden,evermenigvuldigt het getal met1met het gegeven aantal nullen.
1e3 = 1 * 1000 // e3 means *10001.23e6 = 1.23 * 1000000 // e6 means *1000000Nu gaan we iets heel kleins schrijven. Zeg, 1 microseconde (een miljoenste van een seconde):
let ms = 0.000001;Net als eerder kan het gebruik van "e" helpen. Als we de nullen niet expliciet willen schrijven, kunnen we hetzelfde zeggen als:
let ms = 1e-6; // six zeroes to the left from 1Als we de nullen tellen in 0.000001, dan zijn dat er 6. Dus is het natuurlijk 1e-6.
Met andere woorden, een negatief getal na "e" betekent een deling door 1 met het gegeven aantal nullen:
// -3 divides by 1 with 3 zeroes1e-3 = 1 / 1000 (=0.001)// -6 divides by 1 with 6 zeroes1.23e-6 = 1.23 / 1000000 (=0.00000123)Hex, binaire en octale getallen
Hexadecimale getallen worden in JavaScript veel gebruikt om kleuren weer te geven, karakters te coderen, en voor vele andere dingen. Er bestaat dus een kortere manier om ze te schrijven: 0x en dan het getal.
Bijvoorbeeld:
alert( 0xff ); // 255alert( 0xFF ); // 255 (the same, case doesn't matter)Binaire en octale getallenstelsels worden zelden gebruikt, maar worden ook ondersteund met behulp van de 0b en 0o prefixen:
let a; // binary form of 255let b = 0o377; // octal form of 255alert( a == b ); // true, the same number 255 at both sidesEr zijn slechts 3 cijfersystemen met dergelijke ondersteuning. Voor andere getallenstelsels moeten we de functie parseInt gebruiken (die we later in dit hoofdstuk zullen zien).
toString(base)
De methode num.toString(base) geeft een string-weergave van num in het getallenstelsel met de gegeven base.
Voorbeeld:
let num = 255;alert( num.toString(16) ); // ffalert( num.toString(2) ); // 11111111De base kan variëren van 2 tot 36. Standaard is dit 10. 
Common use cases hiervoor zijn:
- 
base=16 wordt gebruikt voor hex-kleuren, tekencoderingen etc, cijfers kunnen 0..9ofA..Fzijn.
- 
base=2 is vooral bedoeld voor het debuggen van bitwise-bewerkingen, cijfers kunnen zijn 0of1.
- 
basis=36 is het maximum, cijfers kunnen 0..9ofA..Zzijn. Het hele latijnse alfabet wordt gebruikt om een getal weer te geven. Een grappig, maar nuttig geval voor36is wanneer we een lange numerieke identificator in iets korter moeten veranderen, bijvoorbeeld om een korte url te maken. We kunnen het eenvoudigweg in het numerieke systeem weergeven met basis36:alert( 123456..toString(36) ); // 2n9cTwee puntjes om een methode aan te roepenLet op dat twee puntjes in 123456..toString(36)geen typfout is. Als we een methode direct op een getal willen aanroepen, zoalstoStringin het voorbeeld hierboven, dan moeten we er twee puntjes..achter zetten.Als we een enkel puntje hadden geplaatst: 123456.toString(36), dan zou er een fout zijn, omdat de syntaxis van JavaScript het decimale deel na de eerste punt impliceert. En als we nog een punt plaatsen, dan weet JavaScript dat het decimale deel leeg is en gaat nu de methode.Ook zou je (123456).toString(36)kunnen schrijven.AfrondingEén van de meest gebruikte bewerkingen bij het werken met getallen is afronding. Er zijn verschillende ingebouwde functies voor afronding: Math.floorAfronding naar beneden:3.1wordt3, en-1.1wordt-2Math.ceilRondt af naar boven:3.1wordt4, en-1.1wordt-1Math.roundRondt af naar het dichtstbijzijnde gehele getal:3.1wordt33.6wordt4, het middelste geval:3.5rondt ook af naar boven tot4Math.trunc(niet ondersteund door Internet Explorer) Verwijdert alles achter de komma zonder afronding:3.1wordt3-1.1wordt-1.Hier is de tabel om de verschillen tussen hen samen te vatten: Math.floorMath.ceilMath.roundMath.trunc3.134333.63443-1.1-2-1-1-1-1.6-2-1-2-1Deze functies behandelen alle mogelijke manieren om met het decimale deel van een getal om te gaan. Maar wat als we het getal willen afronden op n-thcijfer na de decimaal?We hebben bijvoorbeeld 1.2345en willen het afronden op 2 cijfers, waardoor we alleen1.23krijgen.Er zijn twee manieren om dat te doen: - 
Multiply-and-divide. Om het getal bijvoorbeeld af te ronden op het 2e cijfer achter de komma, kunnen we het getal vermenigvuldigen met 100(of een grotere macht van 10), de afrondingsfunctie aanroepen en dan terug delen.let num = 1.23456;alert( Math.round(num * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23
- 
De methode toFixed(n) rondt het getal af op ncijfers na de punt en geeft een string-weergave van het resultaat.let num = 12.34;alert( num.toFixed(1) ); // "12.3"
 
- 
Dit rondt naar boven of beneden af op de dichtstbijzijnde waarde, vergelijkbaar met Math.round:
let num = 12.36;alert( num.toFixed(1) ); // "12.4"Let op dat het resultaat van toFixed een string is. Als het decimale deel korter is dan vereist, worden er nullen aan het eind toegevoegd: 
let num = 12.34;alert( num.toFixed(5) ); // "12.34000", added zeroes to make exactly 5 digitsWe kunnen het omzetten in een getal met behulp van de unary plus of een Number() oproep: +num.toFixed(5).
Onnauwkeurige berekeningen
Intern wordt een getal weergegeven in het 64-bits formaat IEEE-754, dus er zijn precies 64 bits om een getal op te slaan: 52 daarvan worden gebruikt om de cijfers op te slaan, 11 daarvan slaan de positie van de decimale punt op (ze zijn nul voor gehele getallen), en 1 bit is voor het teken.
Als een getal te groot is, zou het de 64-bits opslagruimte overlopen, wat mogelijk een oneindigheid oplevert:
alert( 1e500 ); // InfinityWat misschien iets minder voor de hand ligt, maar wel vaak voorkomt, is het verlies van precisie.
Bedenk deze (vals!) test:
alert( 0.1 + 0.2 == 0.3 ); // falseDat is juist, als we controleren of de som van 0.1 en 0.20.3 is, krijgen we false.
Schrikbarend! Wat is het dan als het niet 0.3 is?
alert( 0.1 + 0.2 ); // 0.30000000000000004Ouch! Er zijn hier meer gevolgen dan een onjuiste vergelijking. Stel je voor dat je een e-shopping site maakt en de bezoeker legt $0.10 en $0.20 goederen in zijn winkelwagen. Het totaal van de bestelling zal $0.30000000000000004 zijn. Dat zou niemand verbazen.
Maar waarom gebeurt dit?
Een getal wordt in het geheugen opgeslagen in zijn binaire vorm, een opeenvolging van bits – enen en nullen. Maar breuken zoals 0.10.2 die er in het decimale getallensysteem eenvoudig uitzien, zijn in feite oneindige breuken in hun binaire vorm.
Met andere woorden, wat is 0.1? Het is één gedeeld door tien 1/10, een tiende. In het decimale getallenstelsel zijn dergelijke getallen gemakkelijk weer te geven. Vergelijk het met eenderde: 1/3. Het wordt een eindeloze breuk 0.33333(3).
Deling door machten 10 werkt dus gegarandeerd goed in het decimale stelsel, maar deling door 3 werkt dat niet. Om dezelfde reden werkt in het binaire getallenstelsel deling door machten van 2 gegarandeerd, maar 1/10 wordt een eindeloze binaire breuk.
Er is gewoon geen manier om precies 0.1 of precies 0.2 op te slaan met het binaire systeem, net zoals er geen manier is om een derde op te slaan als een decimale breuk.
Het numerieke formaat IEEE-754 lost dit op door af te ronden naar het dichtstbijzijnde mogelijke getal. Door deze afrondingsregels zien we dat “kleine precisieverlies” normaal gesproken niet, maar het bestaat wel.
We kunnen dit in actie zien:
alert( 0.1.toFixed(20) ); // 0.10000000000000000555En als we twee getallen optellen, tellen hun “precisieverliezen” bij elkaar op.
Daarom is 0.1 + 0.2 niet precies 0.3.
Hetzelfde probleem bestaat in veel andere programmeertalen.
PHP, Java, C, Perl, Ruby geven precies hetzelfde resultaat, omdat ze op hetzelfde numerieke formaat zijn gebaseerd.
Kunnen we het probleem omzeilen? Zeker, de meest betrouwbare methode is om het resultaat af te ronden met behulp van een methode toFixed(n):
let sum = 0.1 + 0.2;alert( sum.toFixed(2) ); // 0.30Merk op dat toFixed altijd een string teruggeeft. Het zorgt ervoor dat het 2 cijfers achter de komma heeft. Dat is eigenlijk handig als we een e-shopping hebben en $0.30 moeten tonen. Voor andere gevallen kunnen we de unary plus gebruiken om er een getal van te maken:
let sum = 0.1 + 0.2;alert( +sum.toFixed(2) ); // 0.3We kunnen de getallen ook tijdelijk met 100 (of een groter getal) vermenigvuldigen om er gehele getallen van te maken, de wiskunde doen, en dan terug delen. Omdat we dan met gehele getallen rekenen, neemt de fout iets af, maar we krijgen hem nog steeds bij het delen:
alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001Dus, de vermenigvuldigen/vermenigvuldigen aanpak vermindert de fout, maar neemt hem niet helemaal weg.
Soms kunnen we proberen om breuken helemaal te vermijden. Als we bijvoorbeeld te maken hebben met een winkel, dan kunnen we de prijzen in centen opslaan in plaats van in dollars. Maar wat als we een korting van 30% toepassen? In de praktijk is het zelden mogelijk om breuken volledig te omzeilen. Rond ze gewoon af om “staartjes” af te snijden als dat nodig is.
Probeer dit eens uit te voeren:
// Hello! I'm a self-increasing number!alert( 9999999999999999 ); // shows 10000000000000000Dit heeft met hetzelfde probleem te maken: een verlies aan precisie. Er zijn 64 bits voor het getal, 52 daarvan kunnen worden gebruikt om cijfers op te slaan, maar dat is niet genoeg. Dus verdwijnen de minst significante cijfers.
JavaScript geeft geen foutmelding in zulke gevallen. Het doet zijn best om het getal in het gewenste formaat te passen, maar helaas is dit formaat niet groot genoeg.
Een ander grappig gevolg van de interne representatie van getallen is het bestaan van twee nullen: 0 en -0.
Dat komt omdat een teken wordt gerepresenteerd door een enkele bit, dus het kan worden gezet of niet gezet voor elk getal inclusief een nul.
In de meeste gevallen is het onderscheid niet merkbaar, omdat operatoren geschikt zijn om ze als hetzelfde te behandelen.
Tests: isFinite en isNaN
Herken je deze twee speciale numerieke waarden nog?
-  Infinity(en-Infinity) is een speciale numerieke waarde die groter (kleiner) is dan iets.
-  NaNstaat voor een fout.
Ze behoren tot het type number, maar zijn geen “normale” getallen, dus zijn er speciale functies om ze te controleren:
- 
isNaN(value)converteert zijn argument naar een getal en test dan of hetNaNis:alert( isNaN(NaN) ); // truealert( isNaN("str") ); // trueMaar hebben we deze functie nodig? Kunnen we niet gewoon de vergelijking === NaNgebruiken? Sorry, maar het antwoord is nee. De waardeNaNis uniek in die zin dat het aan niets gelijk is, ook niet aan zichzelf:alert( NaN === NaN ); // falseisFinite(value)converteert het argument naar een getal en geefttrueterug als het een gewoon getal is, nietNaN/Infinity/-Infinity:alert( isFinite("15") ); // truealert( isFinite("str") ); // false, because a special value: NaNalert( isFinite(Infinity) ); // false, because a special value: InfinitySoms wordt isFinitegebruikt om te valideren of een string waarde een regulier getal is:let num = +prompt("Enter a number", '');// will be true unless you enter Infinity, -Infinity or not a numberalert( isFinite(num) );Let op dat een lege of een spatie-string wordt behandeld als 0in alle numerieke functies inclusiefisFinite.Vergelijken metObject.isEr is een speciale ingebouwde methode Object.isdie waarden vergelijkt zoals===, maar die betrouwbaarder is voor twee randgevallen:- Het werkt met NaNObject.is(NaN, NaN) === true, dat is een goede zaak.
- Waarden 0en-0zijn verschillend:Object.is(0, -0) === false, technisch is dat waar, want intern heeft het getal een tekenbit dat verschillend kan zijn, zelfs als alle andere bits nullen zijn.
 In alle andere gevallen is Object.is(a, b)hetzelfde alsa === b.Deze manier van vergelijken wordt vaak gebruikt in JavaScript specificatie. Wanneer een intern algoritme twee waarden moet vergelijken om te zien of ze precies hetzelfde zijn, gebruikt het Object.is(intern SameValue genoemd).parseInt en parseFloatNumerieke conversie met behulp van een plus +ofNumber()is strikt. Als een waarde niet precies een getal is, mislukt het:alert( +"100px" ); // NaNDe enige uitzondering zijn spaties aan het begin of aan het eind van de string, die worden genegeerd. Maar in het echte leven hebben we vaak waarden in eenheden, zoals "100px"of"12pt"in CSS. Ook komt in veel landen het valutasymbool achter het bedrag, dus we hebben"19€"en willen daar een numerieke waarde uit halen.Daar zijn parseIntenparseFloatvoor.Ze “lezen” een getal uit een string tot ze niet meer kunnen. In geval van een fout wordt het verzamelde getal geretourneerd. De functie parseIntretourneert een geheel getal, terwijlparseFloateen floating-point getal zal retourneren:alert( parseInt('100px') ); // 100alert( parseFloat('12.5em') ); // 12.5alert( parseInt('12.3') ); // 12, only the integer part is returnedalert( parseFloat('12.3.4') ); // 12.3, the second point stops the readingEr zijn situaties waarin parseInt/parseFloatNaNzal teruggeven. Dit gebeurt wanneer er geen cijfers konden worden gelezen:alert( parseInt('a123') ); // NaN, the first symbol stops the processHet tweede argument vanparseInt(str, radix)DeparseInt()functie heeft een optionele tweede parameter. Deze specificeert de basis van het getallenstelsel, zodatparseIntook reeksen hex-getallen, binaire getallen enzovoort kan ontleden:alert( parseInt('0xff', 16) ); // 255alert( parseInt('ff', 16) ); // 255, without 0x also worksalert( parseInt('2n9c', 36) ); // 123456Andere wiskundige functiesJavaScript heeft een ingebouwd Math object dat een kleine bibliotheek van wiskundige functies en constanten bevat. Een paar voorbeelden: Math.random()Retourneert een willekeurig getal van 0 tot 1 (1 niet meegerekend). alert( Math.random() ); // 0.1234567894322alert( Math.random() ); // 0.5435252343232alert( Math.random() ); // ... (any random numbers)Math.max(a, b, c...)Math.min(a, b, c...)Krijgt de grootste/kleinste uit het willekeurig aantal argumenten. alert( Math.max(3, 5, -10, 0, 1) ); // 5alert( Math.min(1, 2) ); // 1Math.pow(n, power)Returns nverheven tot de gegeven macht.alert( Math.pow(2, 10) ); // 2 in power 10 = 1024Er zijn meer functies en constanten in het Mathobject, inclusief trigonometrie, die je kunt vinden in de docs voor het Math object.SamenvattingOm getallen met veel nullen te schrijven: - Voeg "e"met de nullen tellen toe aan het getal. Zoals:123e6is hetzelfde als123met 6 nullen123000000.
- Een negatief getal na "e"zorgt ervoor dat het getal gedeeld wordt door 1 met gegeven nullen. Bijv.123e-6betekent0.000123123miljoensten).
 Voor verschillende getallenstelsels: - Kan getallen direct schrijven in hex (0x), octaal (0o) en binair (0b) stelsel.
-  parseInt(str, base)parseert de stringstrin een geheel getal in getallenstelsel met gegevenbase2 ≤ base ≤ 36.
-  num.toString(base)converteert een getal naar een string in het getallenstelsel met de gegevenbase.
 Voor het omzetten van waarden als 12pten100pxnaar een getal:- Gebruik parseInt/parseFloatvoor de “zachte” conversie, die een getal uit een tekenreeks leest en vervolgens de waarde teruggeeft die ze vóór de fout konden lezen.
 Voor breuken: - Rond af met Math.floorMath.ceilMath.truncMath.roundofnum.toFixed(precision).
- Houd er rekening mee dat er precisieverlies optreedt als je met breuken werkt.
 Meer wiskundige functies: - Zie het Math-object als je ze nodig hebt. De bibliotheek is erg klein, maar kan in de basisbehoeften voorzien.