JavaScript Number Data Type
Number Basics
JavaScript has a single number type that covers both integers and decimals - there's no separate int or float. All numbers are stored as 64-bit double-precision floating-point values following the IEEE 754 standard. This is convenient because you don't have to think about types, but it comes with one well-known consequence: decimal arithmetic isn't always exact. Numbers can be written in decimal, hexadecimal (0x prefix), octal (0o prefix), binary (0b prefix), or scientific e-notation.
1// All of these are the same type: number
2let count = 42;
3let price = 19.99;
4const temperature = -5.5;
5
6// Alternative representations
7let scientific = 2.5e4; // 25000
8let hex = 0xFF; // 255
9let octal = 0o10; // 8
10let binary = 0b1010; // 10
11
12console.log(scientific); // 25000
13console.log(hex); // 255
14console.log(typeof 42); // "number"
15console.log(typeof 3.14); // "number" - same typeNumber Characteristics
Single number type- One type covers both integers and decimals. No int, float, or double distinction.64-bit floating point- All numbers use IEEE 754 double-precision format, which determines both the range and the precision limits.Multiple formats- Decimal, hex (0xFF), octal (0o10), binary (0b1010), and scientific notation (1e6) all produce number values.Precision limits- Safe integers range from -(2^53 - 1) to (2^53 - 1). Decimal fractions have rounding limits due to binary storage.
Number Declaration
Numbers are created by writing the literal value. For values that won't change, const is standard. Scientific notation is useful for very large or very small values - 1.5e6 is more readable than 1500000 at a glance. Hexadecimal notation appears in color values, bitmasks, and byte manipulation. The Number() function converts other types to numbers, but new Number() creates a Number object rather than a primitive - avoid the constructor form.
1// Integer and float literals
2const age = 25;
3const pi = 3.14159;
4const small = 0.0001;
5
6// Scientific notation
7const large = 1.5e6; // 1500000
8const tiny = 2.3e-4; // 0.00023
9
10// Other bases
11const hex = 0xA; // 10
12const color = 0xFF5733; // 16737843
13const octal = 0o10; // 8
14const binary = 0b1101; // 13
15
16console.log(large); // 1500000
17console.log(color); // 16737843
18
19// Number() for conversion
20const fromString = Number("42"); // 42
21const fromBool = Number(true); // 1
22const fromNull = Number(null); // 0
23const invalid = Number("hello"); // NaN
24
25// Avoid new Number() - creates an object, not a primitive
26// const obj = new Number(100); // [Number: 100] - not what you wantNumber Formats
Integer literals- Whole numbers: 42, -15, 0. Stored as 64-bit float internally but behave as integers within the safe range.Float literals- Decimal numbers: 3.14, -2.5. Subject to IEEE 754 rounding for fractions like 0.1.Scientific notation- 1e6 is 1,000,000. 2.3e-4 is 0.00023. Useful for very large or small constants.Other bases- Hex (0xFF), octal (0o17), binary (0b1010). All evaluate to regular decimal numbers.
Number Properties and Methods
The Number object has static properties for the limits of the number type and static methods for type checking and parsing. Instance methods format a number for display. The most common formatting methods are toFixed (fixed decimal places) and toPrecision (total significant digits). Both return strings, not numbers. For checking number validity, prefer Number.isNaN and Number.isFinite over the global isNaN and isFinite because the global versions coerce their argument first, which produces surprising results.
1// Static properties - the limits
2console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
3console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991
4console.log(Number.MAX_VALUE); // 1.7976931348623157e+308
5console.log(Number.POSITIVE_INFINITY); // Infinity
6console.log(Number.NaN); // NaN
7
8// Instance methods - formatting
9const n = 123.45678;
10console.log(n.toFixed(2)); // "123.46" - 2 decimal places
11console.log(n.toPrecision(5)); // "123.46" - 5 significant digits
12console.log(n.toString()); // "123.45678"
13console.log(n.toString(2)); // binary representation
14console.log(n.toString(16)); // hex representation
15
16// Static methods for checking
17console.log(Number.isInteger(42)); // true
18console.log(Number.isInteger(42.5)); // false
19console.log(Number.isFinite(42)); // true
20console.log(Number.isFinite(Infinity)); // false
21console.log(Number.isNaN(NaN)); // true
22console.log(Number.isNaN("text")); // false - no coercion
23
24// vs global versions that coerce first
25console.log(isNaN("text")); // true - coerces "text" to NaN first
26console.log(Number.isNaN("text")); // false - no coercion
27
28// Parsing
29console.log(Number.parseInt("42px")); // 42 - stops at non-numeric
30console.log(Number.parseFloat("3.14cm")); // 3.14Key Number Methods
toFixed(n)- Returns a string with n decimal places, rounding as needed. Returns a string, not a number.toPrecision(n)- Returns a string with n total significant digits.Number.isNaN() and Number.isFinite()- Prefer these over global isNaN() and isFinite() - the static versions don't coerce the argument first.parseInt() and parseFloat()- Parse a string until a non-numeric character is found. parseInt accepts a radix as the second argument.
Arithmetic and the Math Object
The standard arithmetic operators work as expected. The exponentiation operator ** was added in ES2016 and replaces Math.pow for most uses. The Math object provides the mathematical functions that aren't built into operators - rounding, roots, trigonometry, logarithms, random values. Math.random() returns a float between 0 (inclusive) and 1 (exclusive), which you scale and floor to get a random integer in a range.
1// Arithmetic operators
2const a = 10, b = 3;
3console.log(a + b); // 13
4console.log(a - b); // 7
5console.log(a * b); // 30
6console.log(a / b); // 3.3333...
7console.log(a % b); // 1 (remainder)
8console.log(a ** b); // 1000 (exponentiation, ES2016)
9
10// Increment and decrement
11let count = 5;
12console.log(count++); // 5 (returns then increments)
13console.log(count); // 6
14console.log(++count); // 7 (increments then returns)
15
16// Math object
17console.log(Math.PI); // 3.141592653589793
18console.log(Math.sqrt(16)); // 4
19console.log(Math.round(3.7)); // 4
20console.log(Math.floor(3.9)); // 3 - rounds down
21console.log(Math.ceil(3.1)); // 4 - rounds up
22console.log(Math.abs(-5)); // 5
23console.log(Math.max(1,5,3)); // 5
24console.log(Math.min(1,5,3)); // 1
25
26// Random number in a range
27function randomInt(min, max) {
28 return Math.floor(Math.random() * (max - min + 1)) + min;
29}
30console.log(randomInt(1, 10)); // random integer 1-10Special Number Values: NaN, Infinity, and Float Precision
Three special number situations come up often enough to know. Infinity (and -Infinity) results from dividing by zero or exceeding the number range. NaN (Not a Number) results from invalid math operations - multiplying a string by a number, taking the square root of a negative, dividing zero by zero. The NaN value is uniquely unequal to itself: NaN === NaN is false. The floating-point precision issue - 0.1 + 0.2 producing 0.30000000000000004 - is the most surprising for people coming from languages with decimal types.
1// Infinity
2console.log(1 / 0); // Infinity
3console.log(-1 / 0); // -Infinity
4console.log(Infinity + 1); // Infinity
5console.log(isFinite(Infinity)); // false
6
7// NaN
8console.log(0 / 0); // NaN
9console.log("text" * 5); // NaN
10console.log(Math.sqrt(-1)); // NaN
11
12// NaN is not equal to itself
13console.log(NaN === NaN); // false - unique behavior
14console.log(Number.isNaN(NaN)); // true - the correct check
15
16// Floating point precision
17console.log(0.1 + 0.2); // 0.30000000000000004
18console.log(0.1 + 0.2 === 0.3); // false
19
20// Tolerance comparison for float equality
21function almostEqual(a, b, tolerance = 1e-10) {
22 return Math.abs(a - b) < tolerance;
23}
24console.log(almostEqual(0.1 + 0.2, 0.3)); // true
25
26// Safe integer limits
27console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
28console.log(Number.isSafeInteger(9007199254740992)); // false
29
30// Beyond safe range - use BigInt
31const big = 9007199254740993n;
32console.log(big); // 9007199254740993nNumber Conversion and Parsing
Converting between numbers and strings is common. Number() is the strictest conversion - the entire string must be a valid number or it returns NaN. parseInt and parseFloat are lenient - they parse as many characters as make sense and stop at the first character that doesn't fit. This makes parseInt useful for strings like '42px' but also means parseInt('3.14') returns 3 because the dot isn't valid in an integer. The unary plus (+str) converts a string to a number the same way Number() does but is less readable.
1// String to number
2const str = "42";
3console.log(Number(str)); // 42 - strict
4console.log(parseInt(str)); // 42
5console.log(parseFloat(str)); // 42
6console.log(+str); // 42 - unary plus, less readable
7
8// Parsing with non-numeric characters
9console.log(parseInt("42px")); // 42 - stops at p
10console.log(parseFloat("3.14cm")); // 3.14 - stops at c
11console.log(Number("42px")); // NaN - strict
12
13// parseInt with radix
14console.log(parseInt("101", 2)); // 5 - binary to decimal
15console.log(parseInt("0xFF")); // 255 - hex detection
16console.log(parseInt("10", 10)); // 10 - always specify 10 for decimal
17
18// Number to string
19const num = 42;
20console.log(String(num)); // "42" - explicit
21console.log(num.toString()); // "42"
22console.log(num.toString(2)); // "101010" - binary
23console.log(255..toString(16)); // "ff" - hex
24// num + "" works but looks accidental
25
26// Coercion surprises
27console.log("5" + 3); // "53" - + with string concatenates
28console.log("5" - 3); // 2 - - converts to number
29console.log("5" * "2"); // 10 - * converts bothNumber Best Practices
Use const for numeric constants and give them descriptive names - TAX_RATE is clearer than 0.07 appearing in calculations throughout the code. For decimal equality checks, use tolerance comparisons rather than ===. Specify the radix explicitly when using parseInt - parseInt('10') works but parseInt('010') in some older engines interpreted it as octal. For financial calculations, work in integers (cents) rather than floats (dollars) to avoid accumulated rounding errors. Use Number.isNaN and Number.isFinite rather than the global versions for cleaner type checking.
1// Named constants over magic numbers
2const TAX_RATE = 0.07;
3const MAX_ITEMS = 100;
4const TIMEOUT_MS = 5000;
5
6// Tolerance for float equality
7function areEqual(a, b, tolerance = 1e-10) {
8 return Math.abs(a - b) < tolerance;
9}
10console.log(areEqual(0.1 + 0.2, 0.3)); // true
11
12// Integer math for financial calculations
13const priceInCents = 1999; // $19.99
14const taxCents = Math.round(priceInCents * 0.07); // 140
15const totalCents = priceInCents + taxCents; // 2139
16console.log(`$${(totalCents / 100).toFixed(2)}`); // "$21.39"
17
18// Always specify radix with parseInt
19console.log(parseInt("10", 10)); // 10 decimal - unambiguous
20console.log(parseInt("10", 2)); // 2 binary
21console.log(parseInt("10", 16)); // 16 hex
22
23// Prefer Number.isNaN over global isNaN
24console.log(isNaN("hello")); // true - coerces string first
25console.log(Number.isNaN("hello")); // false - no coercion, more accurate
26
27// Validity check
28function isValidNumber(v) {
29 return typeof v === 'number' && Number.isFinite(v);
30}
31console.log(isValidNumber(42)); // true
32console.log(isValidNumber(NaN)); // false
33console.log(isValidNumber(Infinity)); // false
34
35// BigInt for integers beyond safe range
36const safeMax = Number.MAX_SAFE_INTEGER;
37const tooLarge = safeMax + 1;
38console.log(Number.isSafeInteger(tooLarge)); // false
39const bigValue = BigInt(safeMax) + 1n; // use BigInt