The `Number` Class in JavaScript

The `Number` Class in JavaScript

This article explains the Number class in JavaScript.

We will carefully explain the characteristics of Number, common pitfalls, useful APIs, and practical examples step by step.

YouTube Video

The Number Class in JavaScript

Number is the fundamental numeric type in JavaScript and is represented as an IEEE-754 double-precision floating point (64-bit).

Basics: Number Representation and Type Checking

In JavaScript, all numbers are represented as the primitive number type.

 1// Primitive numbers and Number object
 2const a = 42;                 // primitive number
 3const b = 3.14;               // primitive float
 4const c = Number(10);         // primitive via constructor call (function form)
 5const d = new Number(10);     // Number object (wrapper)
 6
 7console.log(typeof a);        // "number"
 8console.log(typeof d);        // "object"
 9console.log(c == d);          // true  (value coerces)
10console.log(c === d);         // false (different types)
  • This code demonstrates the difference between a primitive number and the Number wrapper object. Normally, primitives are used instead of wrappers.

Special Values: NaN, Infinity, and Constants

Number provides special values (NaN, Infinity) and constants.

 1// Special numeric values and constants
 2console.log(Number.NaN);                 // NaN
 3console.log(Number.POSITIVE_INFINITY);   // Infinity
 4console.log(Number.NEGATIVE_INFINITY);   // -Infinity
 5
 6console.log(Number.MAX_VALUE);           // largest positive representable
 7console.log(Number.MIN_VALUE);           // smallest positive representable (closest to 0)
 8console.log(Number.MAX_SAFE_INTEGER);    // 9007199254740991
 9console.log(Number.MIN_SAFE_INTEGER);    // -9007199254740991
10console.log(Number.EPSILON);             // smallest difference ~2.220446049250313e-16
  • Integers greater than or equal to MAX_SAFE_INTEGER may not be represented accurately. Consider using BigInt if accuracy is required. EPSILON is used for floating-point comparisons.

Number Conversion: Number(), parseInt, parseFloat, and + Operator

There are several ways to convert a string to a number, each with different behaviors.

 1// Converting strings to numbers
 2console.log(Number("42"));        // 42
 3console.log(Number("  3.14 "));   // 3.14
 4console.log(+ "7");               // 7 (unary +)
 5
 6console.log(parseInt("42px"));    // 42
 7console.log(parseFloat("3.14abc"));// 3.14
 8
 9// Careful with parseInt and radix
10console.log(parseInt("08"));      // 8
11console.log(parseInt("08", 10));  // 8 (explicit radix is safer)
  • Number() returns NaN unless the whole string is strictly in numeric format, whereas parseInt and parseFloat parse the readable numeric part from the beginning of the string. It is safer to always explicitly specify the radix when using parseInt.

Handling and Checking NaN: isNaN and Number.isNaN

NaN (Not-A-Number) is special in that NaN !== NaN. There are differences in how they check; the global isNaN performs type conversion and may result in false positives, so Number.isNaN is recommended.

1// NaN detection differences
2console.log(NaN === NaN);             // false
3
4console.log(isNaN("foo"));            // true  -> because "foo" coerces to NaN
5console.log(Number.isNaN("foo"));     // false -> "foo" is not the numeric NaN
6
7console.log(Number.isNaN(NaN));       // true
  • Use Number.isNaN for checking numbers and validating calculation results to avoid unnecessary type conversion.

Floating-Point Errors and Comparisons Using Number.EPSILON

Due to IEEE-754, errors such as 0.1 + 0.2 !== 0.3 occur. For strict comparisons, it is common to use the difference and Number.EPSILON.

1// Floating point precision example and EPSILON comparison
2const sum = 0.1 + 0.2;
3console.log(sum === 0.3);             // false
4
5function nearlyEqual(a, b, epsilon = Number.EPSILON) {
6  return Math.abs(a - b) <= epsilon * Math.max(1, Math.abs(a), Math.abs(b));
7}
8
9console.log(nearlyEqual(sum, 0.3));   // true
  • When allowing for errors in comparison, a robust implementation like nearlyEqual that also performs scaling as well as using absolute differences is recommended.

Checking Integers and Safe Integers (isInteger, isSafeInteger)

There are APIs to check whether a value is an integer and whether it is within the safe integer range.

1// Integer and safe integer checks
2console.log(Number.isInteger(3));                 // true
3console.log(Number.isInteger(3.0));               // true
4console.log(Number.isInteger(3.1));               // false
5
6console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER)); // true
7console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)); // false
  • When accuracy of large integers is necessary, use Number.isSafeInteger to check, and consider using BigInt for numbers exceeding that range.

Display and Formatting: toFixed, toPrecision, toString

There are methods available to control the display of numbers. toFixed returns a string with a specified number of decimal places, but care should be taken with rounding.

1// Formatting numbers for display
2const x = 1.23456;
3console.log(x.toFixed(2));         // "1.23"   (string)
4console.log(x.toPrecision(3));     // "1.23"   (string with total significant digits)
5console.log((255).toString(16));   // "ff"     (hexadecimal string)
  • toFixed returns a string, so be aware of values after converting them to numbers for calculations.

Cautions Regarding String Concatenation and + Operator

The + operator is used for both numeric addition and string concatenation, so unintended results may occur depending on the data types involved.

1// Pitfall with + operator and type coercion
2console.log(1 + 2 + "px");    // "3px"
3console.log("px" + 1 + 2);    // "px12"
4console.log(1 + "2" - 0);     // 3  (string coerced to number for subtraction)
  • When strings and numbers are mixed, it is safer to explicitly use String(), Number(), or template literals to avoid implicit type conversion.

Advanced Use Cases: Number.parseInt / Number.parseFloat, valueOf

Number.parseInt and Number.parseFloat are aliases of the global functions. valueOf is used to retrieve the primitive value from a Number object, but it is rarely needed in practice.

1// Number.parseInt/parseFloat aliases and valueOf example
2console.log(Number.parseInt("100", 10));   // 100
3console.log(Number.parseFloat("3.14"));    // 3.14
4
5const nObj = new Number(5);
6console.log(nObj.valueOf());               // 5
7console.log(nObj + 1);                     // 6  (object coerced to primitive)
  • When using Number.parseInt and Number.parseFloat, be careful with the radix and trimming the input. Wrapper objects are usually avoided.

Reference: Small Utility Example - Number Validation Functions

Here are small utility functions that collect commonly used checks. This makes tasks such as input validation easier.

 1// Small number utility functions
 2function toNumberStrict(value) {
 3  // Return a Number or throw for invalid numeric strings
 4  const n = Number(value);
 5  if (typeof value === "string" && value.trim() === "") {
 6    throw new Error("Empty string is not a valid number");
 7  }
 8  if (Number.isNaN(n)) {
 9    throw new Error(`Invalid number: ${value}`);
10  }
11  return n;
12}
13
14function almostEqual(a, b, eps = Number.EPSILON) {
15  // Robust relative comparison
16  return Math.abs(a - b) <= eps * Math.max(1, Math.abs(a), Math.abs(b));
17}
  • These are highly versatile functions that can be used repeatedly for input processing and comparisons. Implementations that throw errors are useful for validation purposes.

Summary of Performance and Best Practices

The following are practical points when using Number.

  • Basically, use the primitive number type and avoid new Number().
  • Choose between Number() (strict) or parseInt/parseFloat (partial extraction) for string-to-number conversion depending on your use case.
  • Use Number.isNaN and Number.isFinite for safe checking.
  • For floating-point comparisons, use Number.EPSILON or create a dedicated comparison function.
  • When integer accuracy is required, use Number.isSafeInteger, and if it exceeds the range, use BigInt.
  • You can use toFixed or toPrecision for rounding for display, but note that the return value is a string.

Summary

Number is the basic type for all numbers in JavaScript, including integers, decimals, and special values (NaN and Infinity). It is important to be aware of type conversion and floating-point errors, and to use methods such as Number.isNaN and Number.EPSILON correctly. If the safe integer range is exceeded, use BigInt, and use toFixed or toPrecision for rounding and display.

You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.

YouTube Video