SKU // 33

JavaScript Numbers

JavaScript has only one type of number for everything: whole numbers, decimals, negatives, and very large or very small values. That keeps things simple, but it also explains most of the surprises in this lesson, from 0.1 + 0.2 to numbers that quietly round themselves.

// Writing Numbers

Numbers can be written with or without decimals:

let a = 42;          // whole number
let b = 3.14;        // decimal
let c = -7;          // negative
let d = 1_000_000;   // underscores for readability: same as 1000000

console.log(typeof a, typeof b, d);
number number 1000000

Extra large or extra small numbers can be written in scientific (exponent) notation, where e means "times ten to the power of":

console.log(123e5);     // 123 × 10⁵
console.log(123e-5);    // 123 × 10⁻⁵
12300000 0.00123

// Always 64-bit Floating Point

Many programming languages have several number types: whole-number types of different sizes (byte, short, int, long) and decimal types (float, double). JavaScript has just one. Every number is stored as a 64-bit floating point number, following an international standard called IEEE 754. Those 64 bits are split three ways:

Part Bits Holds
Fraction (mantissa)52 bits (0 to 51)the digits
Exponent11 bits (52 to 62)where the decimal point goes
Sign1 bit (63)positive or negative

You never deal with those bits directly. What matters is the consequence: with only 52 bits for the digits, there is a limit to how precise a number can be.

// Integer Precision

Whole numbers are accurate up to about 15 digits. Past that, they get rounded:

let x = 999999999999999;     // 15 digits
let y = 9999999999999999;    // 16 digits
console.log(x);
console.log(y);
999999999999999 10000000000000000

No error, no warning: the 16-digit number is simply wrong. The exact limit is 9,007,199,254,740,991, covered in JS Number Properties, and the fix for bigger numbers is JS BigInt.

// Floating Point Precision

Decimals have a similar problem. Computers store them in binary, and some simple decimals (like 0.1) cannot be stored exactly in binary, just as 1/3 cannot be written exactly as a decimal (0.3333...). The tiny error shows up in a famous surprise:

console.log(0.1 + 0.2);
console.log(0.1 + 0.2 === 0.3);
0.30000000000000004 false

This is not a JavaScript bug; almost every programming language does the same thing. Three common fixes:

// 1. Multiply to whole numbers first, then divide back
console.log((0.2 * 10 + 0.1 * 10) / 10);

// 2. Round only when displaying
console.log((0.1 + 0.2).toFixed(2));

// 3. Work in whole units: cents instead of dollars
let cents = 10 + 20;
console.log(cents / 100);
0.3 0.30 0.3
Tip: money
For money, store amounts as whole cents and only divide by 100 for display. Whole numbers are exact, so rounding errors cannot pile up over many calculations.

// Adding Numbers and Strings

JavaScript uses + for both adding and joining. Numbers are added; if either side is a string, they are joined:

let x = 10;
let y = 20;
console.log(x + y);                        // two numbers
console.log("10" + "20");                  // two strings
console.log(10 + "20");                    // number and string
30 1020 1020

Two classic mistakes come from JavaScript working left to right:

let x = 10;
let y = 20;
let z = "30";

console.log("The result is: " + x + y);   // expecting 30?
console.log(x + y + z);                     // expecting 102030?
The result is: 1020 3030

Numeric strings

With every other math operator, JavaScript converts numeric strings to numbers:

let x = "100";
let y = "10";
console.log(x / y);   // works
console.log(x * y);   // works
console.log(x - y);   // works
console.log(x + y);   // joins instead!
10 1000 90 10010
Watch out
Relying on automatic conversion is risky, especially because + breaks the pattern. Convert on purpose with Number() before doing math with values that might be strings (see JS Number Methods).

// NaN: Not a Number

NaN is a reserved word meaning "this is not a legal number". It is what you get when math cannot produce a real number:

console.log(100 / "Apple");   // not numeric
console.log(100 / "10");      // numeric string: fine
console.log(0 / 0);
console.log(typeof NaN);        // oddly enough
NaN 10 NaN number

NaN spreads. Any math with it gives NaN, and joining it with a string gives text containing "NaN":

console.log(NaN + 5);
console.log(NaN + "5");
console.log(NaN === NaN);     // not even equal to itself!
NaN NaN5 false

Because NaN is not equal to anything, you cannot test for it with ===. Use isNaN(), or better, Number.isNaN() (JS Number Methods explains the difference):

let result = 100 / "Apple";
console.log(isNaN(result));
console.log(Number.isNaN(result));
true true

// Infinity

Infinity (or -Infinity) is what JavaScript gives you when a number goes beyond the largest number it can store. Squaring a number over and over gets there surprisingly fast:

let myNumber = 2;
while (myNumber != Infinity) {
  myNumber = myNumber * myNumber;
  console.log(myNumber);
}
4 16 256 65536 4294967296 18446744073709552000 3.402823669209385e+38 1.157920892373162e+77 1.3407807929942597e+154 Infinity

Dividing by zero does not crash either. It quietly gives Infinity, which then spreads through later math:

console.log(2 / 0);
console.log(-2 / 0);
console.log(typeof Infinity);
Infinity -Infinity number

// Other Number Bases

By default, numbers are written and shown in base 10. Prefixes let you write them in other bases:

console.log(0xFF);     // hexadecimal (base 16)
console.log(0b1010);   // binary (base 2)
console.log(0o17);     // octal (base 8)
255 10 15

Hex values show up constantly in CSS colors: #FF8800 is three hex numbers for red, green, and blue. Going the other way, toString(base) writes a number in any base from 2 to 36:

let myNumber = 32;
console.log(myNumber.toString(16));   // hex
console.log(myNumber.toString(8));    // octal
console.log(myNumber.toString(2));    // binary
20 40 100000
Watch out: never start a number with 0
An old rule treats a number starting with 0 as octal. So 010 is not ten, it is 8. (In strict mode, it is a SyntaxError instead.) This bites people who pad numbers to line them up, like zip codes or times: let minutes = 010;. Write 10, or keep padded values as strings: "010".

// Numbers as Objects (Don't)

Like strings and booleans, numbers can be created as objects with new. Never do this:

let x = 500;
let y = new Number(500);
let z = new Number(500);

console.log(typeof y);
console.log(x == y);
console.log(x === y);
console.log(y == z);     // two objects are never equal
object true false false

Same story as new String() and new Boolean(): slower code and broken comparisons.

// Quick Check

What does this log?

let a = 5, b = 5;
console.log("Total: " + a + b);
Show answer
Total: 55. Left to right: the string comes first, so each number is joined on as text. Use "Total: " + (a + b) to get Total: 10.

How should you check whether result is NaN?

  1. result === NaN
  2. result == NaN
  3. Number.isNaN(result)
  4. typeof result === "NaN"
Show answer
C. NaN is not equal to anything, including itself, so A and B are always false. D is always false too, because typeof NaN is "number".

What is console.log(010 + 1)?

  1. 11
  2. 9
  3. "0101"
  4. NaN
Show answer
B. The leading zero makes 010 an octal number, which is 8. 8 + 1 is 9. Never start a number with 0.

// Try It

  1. Click Open Playground and run it. Then fix it all three ways shown above
  2. Predict, then check: "5" + 5, "5" - 5, "5" * "5", and 5 + 5 + "5"
  3. Log 9999999999999999 and 99999999999999999. How far off are they?
  4. Print 255 in binary, octal, and hex with toString(). Then log 0xFF, 0o377, and 0b11111111
// Video Walkthroughs
Last updated: Oct 10, 2026, 12:51 AM ET