Number object

JavaScript’s Number covers integers and floating-point values with one implementation: IEEE-754 binary64 (aka “double precision”). That means you get roughly 15–17 decimal digits of precision, support for NaN, Infinity, and signed zero (+0 and -0), and a whole family of helpers on Number.prototype and Number.*. If you’ve ever seen 0.1 + 0.2 produce 0.30000000000000004, you’ve bumped into this representation. MDN’s overview and the spec both confirm that JavaScript has exactly two numeric types: Number (binary64) and BigInt.

A Number is stored as 64 bits: 1 sign bit, 11 bits of exponent (biased), and 52 bits of fraction with an implicit leading 1, giving 53 bits of precision. That’s why only integers in [-(2^53 − 1), 2^53 − 1] are safe: beyond that range, you can’t uniquely represent every integer.

Number.MAX_SAFE_INTEGER;      //  9007199254740991  (2**53 - 1)
Number.MIN_SAFE_INTEGER;      // -9007199254740991
Number.isSafeInteger(42);     // true
Number.isSafeInteger(2**53);  // false

Those “safe integer” constants and checks are part of the standard library so you can proactively guard domain logic.

Literals, bases, and readability

You can write numbers in decimal, binary (0b...), octal (0o...), or hex (0x...). You can also use numeric separators (_) anywhere digits appear to improve readability—just not at the start, end, next to a decimal point, or doubled.

const oneTrillion   = 1_000_000_000_000;
const hexMask       = 0xFF_FF_00_00;
const permissions   = 0b1111_0000_1010_0101;
const precise       = 1_234.567_89;

Special numeric values you should care about

NaN represents an invalid numeric result. Infinity and -Infinity represent overflow and division by zero. Number.MIN_VALUE is the smallest positive subnormal binary64 value (≈ 5e−324), not the most negative number; it’s easy to misinterpret that name.

0 / 0;              // NaN
1 / 0;              // Infinity
-1 / 0;             // -Infinity
Number.MIN_VALUE;   // 5e-324 (smallest positive, not "most negative")

Equality, sameness, and the weirdness of -0

=== works for most comparisons, but it treats +0 and -0 as equal and it considers NaN !== NaN. Object.is follows the spec’s SameValue algorithm: it distinguishes -0 from +0 and treats NaN as the same value as itself. Reach for Object.is when those edge cases matter.

NaN === NaN;               // false
Object.is(NaN, NaN);       // true

0 === -0;                  // true
Object.is(0, -0);          // false

Parsing, coercion, and “is this a number?”

Prefer the Number.* family over the legacy globals. Number.isNaN only returns true for the actual number NaN and doesn’t coerce. Number.parseInt and Number.parseFloat parse strings like their global counterparts but live under Number for modularity.

Number.isNaN('NaN');         // false  (no coercion)
isNaN('NaN');                // true   (legacy coercion)

Number.parseInt('42px', 10); // 42
Number.parseFloat('3.14ms'); // 3.14

Number('  12  ');            // 12   (coerces whole string or fails to NaN)

If you need to validate integers specifically, use Number.isInteger. For the safe 53-bit range, pair it with Number.isSafeInteger.

Number.isInteger(3.0);       // true
Number.isInteger(3.14);      // false

Formatting and rounding without surprises

Three standard formatters exist on the instance:

const n = 1234.56789;

n.toFixed(2);       // "1234.57"  -> fixed decimal places
n.toPrecision(4);   // "1235"     -> total significant digits (may use exponent)
n.toExponential(3); // "1.235e+3" -> scientific notation

Use toFixed when you need a consistent number of decimals (like 2 for money display), and toPrecision when you care about significant digits. Both return strings and round as needed.

Dealing with floating-point error like a pro

Binary floating point cannot represent many base-10 fractions exactly; 0.1 and 0.2 are approximations, so their sum is a slightly larger approximation than 0.3. The canonical demo:

0.1 + 0.2 === 0.3;           // false
0.1 + 0.2;                   // 0.30000000000000004

This is inherent to IEEE-754, not a JavaScript bug. You can compare within a tolerance using Number.EPSILON (the gap between 1 and the next representable number).

function nearlyEqual(a, b, epsilon = Number.EPSILON) {
  return Math.abs(a - b) <= epsilon * Math.max(1, Math.abs(a), Math.abs(b));
}

nearlyEqual(0.1 + 0.2, 0.3); // true

When the domain allows it, store scaled integers (cents instead of dollars) and only format at the edges. For truly large integers or exact integer math beyond 53 bits, use BigInt.

Converting to and from Number safely

Everything that looks like a number is not necessarily safe to coerce. Number(value) is an all-or-nothing conversion: the entire string must be numeric (after trimming) or you get NaN. parseInt/parseFloat will read a leading numeric portion and stop at the first invalid character. Choose based on whether partial parses are desirable.

Number('12px');            // NaN
parseInt('12px', 10);      // 12
Number('0xFF');            // 255 (hex string is allowed)
parseInt('0xFF');          // 255 (base inferred as 16 unless radix passed)

Boxing: Number vs number

Number (with capital N) is the constructor for wrapper objects around primitive numbers. You almost never need to create a Number object—primitives are faster and behave better. Methods on Number.prototype are available to primitives via automatic boxing.

typeof 5;                     // "number"
typeof new Number(5);         // "object"

(5).toFixed(1);               // "5.0"  (primitive calls method just fine)

MDN’s Number reference documents both the constructor and the static/instance APIs; prefer primitives unless you’re interfacing with an API that explicitly expects an object.

Commonly used static properties at a glance

Static properties supply important boundaries and sentinels:

Number.MAX_VALUE;             // ≈ 1.7976931348623157e+308  (largest finite)
Number.MIN_VALUE;             // ≈ 5e-324 (smallest positive subnormal)
Number.POSITIVE_INFINITY;     // Infinity
Number.NEGATIVE_INFINITY;     // -Infinity
Number.NaN;                   // NaN (same value as global NaN)

Infinity is also a global. Its behavior matches IEEE-754 rules and can show up from operations like division by zero.

Numbers and BigInts: where the line is

Numbers are ideal for real-valued calculations, measurements, and anything that reasonably fits within 53 bits of integer precision. BigInt gives you arbitrary-precision integers but can’t mix directly with Number, nor is it supported by Math.*. Convert deliberately, only when you must, and keep arithmetic homogeneous.

const big = 2n ** 60n;     // BigInt
//  big + 1   // TypeError: can't mix BigInt and other types
Number(big) + 1;           // OK, but may lose precision for larger values

Practical recipes

Clamp, round, and format for display

function clamp(x, min, max) {
  return Math.min(max, Math.max(min, x));
}

function toMoney(amount) {
  // Display only: do not use for internal accounting
  return Number(amount).toFixed(2);
}

clamp(1.234, 0, 1);       // 1
toMoney(12.5);            // "12.50"

Parse robustly from user input

function readInt(input, { radix = 10 } = {}) {
  const n = Number.parseInt(String(input).trim(), radix);
  return Number.isNaN(n) ? null : n;
}

readInt('  42px');        // 42
readInt('0xff');          // 255
readInt('hello');         // null

Compare with tolerance

// Useful when the exact bit pattern isn’t stable, but magnitude is.
function approximately(a, b, relTol = 1e-12, absTol = Number.EPSILON) {
  const diff = Math.abs(a - b);
  return diff <= Math.max(relTol * Math.max(Math.abs(a), Math.abs(b)), absTol);
}

approximately(Math.sqrt(2)**2, 2);  // true

Performance and correctness tips you’ll actually use

Stick with primitives. Treat Number as a value type and avoid constructing wrapper objects. Prefer Object.is when you must tell -0 from 0 or want NaN equality. Use Number.isNaN and Number.isInteger to avoid implicit coercions that can hide bugs. Reach for Number.EPSILON-based comparisons when dealing with computed results, and reach for BigInt when integer precision beyond 53 bits is a hard requirement. These choices align with the spec’s equality semantics and MDN’s API contracts.

References

SourceWhat it covers
MDN: Number (global object)The Number type, safe integer range, API surface, and special values.
ECMA-262 (HTML, 2024)Normative definition of numeric types in ECMAScript, including Number and BigInt.
ECMA-262 (HTML, “Data Types and Values”)Equality algorithms (Number::equal, SameValue, SameValueZero) that explain Object.is, NaN, and signed zero behavior.
MDN: Number.EPSILONMeaning of EPSILON and its use for tolerance comparisons.
Wikipedia: Double-precision floating-point formatBinary64 layout (sign, exponent, fraction) and precision implications.
MDN: Lexical grammar (numeric separators)Rules and limitations for _ in numeric literals.
MDN: Numbers and strings (guide)Literal syntaxes, exponents, and separators in practice.
MDN: Number.isNaN()Robust NaN checking without coercion.
MDN: Number.isInteger()Integer detection semantics for Number.
MDN: Number.isSafeInteger()Checking for integers within the 53-bit safe range.
MDN: Number.toFixed()Fixed-decimal formatting behavior and rounding.
MDN: Object.is()Differences from === and treatment of NaN and signed zero.
MDN: Infinity / Number.POSITIVE_INFINITY / Number.NEGATIVE_INFINITYInfinity semantics and relationships to arithmetic and overflow.
MDN: Number.MIN_VALUEClarification that it’s the smallest positive value, not “most negative”.
MDN: Number.MAX_SAFE_INTEGERThe upper bound for exact integer representation in Number.