[2018-02-02] dev, javascript, esnext, es2021

(Ad, please don’t block)

The proposal “Numeric Separators” by Sam Goto and Rick Waldron lets us use `_`

as a separator in numeric literals. This blog post explains how that works.

JavaScript has several *numeric literals*:

- Decimal literals:
`123.45`

,`86`

,`12e-5`

- Binary integer literals:
`0b1011`

- Octal integer literals:
`0o765`

- Hexadecimal integer literals:
`0x2FF`

Interestingly, unary minus (`-`

) is an operator and not part of numeric literals (apart from signed exponents in decimal literals).

Grouping digits to make long numbers more readable has a long tradition. For example:

- At the end of 2016, Munich had 1,464,301 inhabitants.
- The distance between Earth and Sun is 149,600,000 km.

The proposal allows underscores as separators in numeric literals:

```
const inhabitantsOfMunich = 1_464_301;
const distanceEarthSunInKm = 149_600_000;
```

With other bases, grouping is important, too:

```
const fileSystemPermission = 0b111_111_000;
const bytes = 0b1111_10101011_11110000_00001101;
const words = 0xFAB_F00D;
```

You can also use the separator in fractions and exponents:

```
const massOfElectronInKg = 9.109_383_56e-31;
const trillionInShortScale = 1e1_2;
```

The key restriction to keep in mind is: You can only put underscores between two digits. Therefore, the following numeric literals are illegal.

```
3_.141
3._141
1_e12
1e_12
_1464301 /* valid variable name! */
1464301_
0_b111111000
0b_111111000
```

Furthermore, you can never use more than one underscore in a row:

```
123__456 /* two underscores – not allowed */
```

The motivation behind these restrictions is to keep things simple.

The proposed arbitrary-precision integers (bigints) enable you to represent larger numbers numerically. Thus, numeric separators are especially helpful with them:

```
const massOfEarthInKg = 6_000_000_000_000_000_000_000_000n;
```

Bigints are often used to represent money in the financial technical sector. Separators can help here, too:

```
const priceInCents = 123_000_00; // 123 thousand dollars
```

The following functions for parsing numbers will not support separators:

`Number()`

`parseInt()`

`parseFloat()`

For example:

```
> Number('123_456')
NaN
> parseInt('123_456')
123
```

The rationale is that numeric separators are for code. Other kinds of input should be processed differently.

One technique for parsing numbers with separators is to remove non-digit characters:

```
const RE_NON_DIGIT = /[^0-9]/gu;
function removeNonDigits(str) {
str = str.replace(RE_NON_DIGIT, '');
return Number(str);
}
```

This is how you use this function:

```
> removeNonDigits('149,600,000')
149600000
> removeNonDigits('1,407,836')
1407836
```

With trailing zeros, exponential notation may be more convenient than grouping zeros. Compare:

```
const timeoutInMilliseconds = 10e3; /* 10 seconds */
const tenSecondTimeout = 10_000; /* 10 seconds */
```

Some data such as phone numbers, credit card numbers and social security numbers, are in some ways numbers, in others not: There may be non-numeric prefixes and separators and leading digits are significant. They should also never be represented in exponential notation.

Therefore – avoid:

```
// Don’t do this:
const phoneNumber = 555_2368;
const creditCardNumber = 378_2822_4631_0005;
const socialSecurityNumber = 111_11_1111;
```