The JavaScript Numeric Separator, introduced in ES2021 (ES12), is a syntactical enhancement designed to improve code readability by allowing developers to use underscores (_) as visual delimiters within numeric literals. Much like commas are used in accounting to separate thousands (e.g., 1,000,000), the numeric separator makes large or complex numbers easier for the human eye to parse without changing the underlying value or type of the number.

The JavaScript engine completely ignores these underscores during the tokenization phase. Consequently, 1_000_000 is strictly identical to 1000000 in terms of memory, performance, and logic.

1. Core Syntax and Usage

The underscore can be placed between any two digits in a numeric literal. This applies to integers, floating-point numbers, and even BigInts.

Standard Integers and Decimals

Instead of squinting at a billion, you can group digits by threes (Western style) or fours (certain Eastern styles).

JavaScript
const billion = 1_000_000_000;
const budget = 125_450_00.50; // Decimals supported
const bytes = 1_024n;         // BigInt supported

Non-Decimal Bases

The separator is particularly useful when dealing with binary, hexadecimal, or octal values, where bit groupings (like nibbles or bytes) are critical for debugging.

JavaScript
const nibbles = 0b1010_0001_1101_1011;
const message = 0xDE_AD_BE_EF;
const permissions = 0o7_5_5;

2. Application Across Different Bases

The power of the numeric separator extends beyond base-10 integers. It is particularly useful for low-level programming where binary or hexadecimal values are common.

Binary and Hexadecimal

In binary, separators are often used to group bits into nibbles (4 bits) or bytes (8 bits). In hexadecimal, they can separate color channels (RGBA) or memory addresses.

JavaScript
// Binary: Grouping by nibbles
const nibbles = 0b1010_0001_1101_1111;

// Hexadecimal: Separating bytes in a color code
const color = 0xFF_AB_C1; // R: 255, G: 171, B: 193

Floating Point and BigInt

Separators can also be placed within the fractional part of a float or appended to the massive integers handled by the BigInt type.

JavaScript
const pi = 3.141_592_653_5;
const hugeValue = 1_000_000_000_000_000n; // BigInt

3. Strict Syntax Rules (What NOT to do)

To ensure consistent parsing, the JavaScript engine enforces strict rules on where the underscore can be placed. Violating these rules will result in a SyntaxError.

Placement Constraints

No Leading or Trailing Underscores: The separator must be between digits.

  • _100 (Illegal: interpreted as a variable name)
  • 100_ (Illegal: SyntaxError)

No Multiple Underscores in a Row: You cannot use 1__000.

No Separators Next to Base Prefixes: You cannot put an underscore immediately after the 0x, 0b, or 0o.

  • 0x_FF (Illegal)

No Separators Next to the Decimal Point: * 1._5 or 1_.5 (Illegal)

JavaScript
// ❌ Invalid placements
const bad1 = _100;    // Variable name, not a number
const bad2 = 100__000; // Only one underscore allowed
const bad3 = 1.0_0;    // Illegal next to decimal
const bad4 = 0b_101;   // Illegal after prefix

4. Interaction with Functions and Parsing

A critical distinction to understand is that the numeric separator is a feature of Numeric Literals (code you write), not Strings containing numbers.

Number() and parseInt()

Standard parsing functions do not recognize the underscore. If you attempt to pass a string with an underscore to these functions, the result will likely be NaN or a truncated number.

JavaScript
// Literal (Works)
const val = 1_000; 

// Parsing (Fails)
Number("1_000");      // NaN
parseInt("1_000");    // 1 (Stops parsing at the non-numeric character '_')
JSON.parse("1_000");  // SyntaxError (JSON does not support separators)

toString()

When you convert a number back to a string, the separators are lost. The engine does not store where the underscores were; they are purely for the developer’s eyes.

JavaScript
const money = 1_000_000;
console.log(money.toString()); // "1000000"

Categorized in:

Javascript,