What is the underscore ( _ ) "inside" of a Javascript number?

Asked

Viewed 224 times

10

I realized I can use underscores (_) between numeric literals in Javascript. For example:

const testA = 1_000_000_000;
console.log(testA); // => 1000000000

const testB = 1000000_0 + '_0_' + 1_0;
console.log(testB); // => "10000000_0_10"

The above form does not return errors, but the following attempts below do not work:

const testA = 1000000_;
const testB = _100;
const testC = 1._000;
const testD = 1000000_.0;

From what I understand, _ serves to facilitate the reading of the numbers. Indeed, read 1_000_000_000 (1 billion) is much easier to understand the number than 1000000000. That would be the only purpose to use _ in the numbers?

I still noticed in some tests that, depending on the way you work, you generate strange behaviors. Playing with behaviors ridiculous unexpected Javascript:

let c;

c = 10_000 - '10000';
console.log(c); // 0

c = 10_000 - '10_000';
console.log(c); // Achei que deveria sair 0, mas retorna NaN

Apparently, I can only use the _ in actual numbers.

That one Feature is new to Javascript? Does it have a name? Because I’ve never seen it used anywhere...

  • 2

    The language defined thus (es2021). The _ is a valid numerical literal separator. https://tc39.es/ecma262/#Prod-Numericliteralseparator

  • ah which is something new. if it was old Feature, would have been worried.

  • Kkkkk. concerned in what sense?

  • pq is something so simple and helps a lot and I would have been worried because I don’t see anyone mention it (talk about or even use in code), nor in video tutorials, blogs, etc... or I’m outdated :( . Writing a day in milliseconds is easier to understand... 86_400_000.

2 answers

11


It’s called Numeric separator or, in English, numerical separator. It was standardized in Ecmascript 2021. See repository with the proposal and discussions. And the section § 12.8.3 of specification.

It is a feature that extends the notation to numerical literals in Javascript, which includes type values number in decimal numerical representation (a usual), binary, octal and hexadecimal. Can also be used in numerical type bigint. The objective is merely aesthetic to facilitate reading, which is certainly benefited in long numerical sequences.

Some examples with the numeric type:

0b111_111; // Binário.     Avalia para: 63
0o777_777; // Octal.       Avalia para: 262143
1_000_000; // Decimal.     Avalia para: 1000000
0xfff_fff; // Hexadecimal. Avalia para: 16777215

And with bigint (denoted by n at the end):

1000000n; // Ou:
1_000_000n;

The place where the underscore will be positioned is not set. You can put it between any digits of the numeric literal. However, there are three notable exceptions:

  • There can’t be two underscores in a row.
  • Cannot be adjacent to the character (b for binary, o for octal and x for hexadecimal) denoting explicit literal numeric based number.
  • Cannot be adjacent to decimal separator (.).
  • Cannot be adjacent to the suffix n, denoting bighorn literal.

Thus, the following cause syntax error:

1__000; // SyntaxError (dois underscores seguidos)
0b_111; // SyntaxError (adjacente ao prefixo de base binária)
0o_777; // SyntaxError (adjacente ao prefixo de base octal)
0x_fff; // SyntaxError (adjacente ao prefixo de base hexadecimal)
12._34; // SyntaxError (adjacente ao separador decimal)
1000_n; // SyntaxError (adjacente ao sufixo de bigint literal)

The formal definition of the syntax can be consulted here. See the compatibility table to find out which browsers support without transpilation.


About conversions

It is worth remembering that the Numeric separators are a purely syntactic resource of language. Nothing changes in how numbers are represented internally, how they are converted (from string to number, for example) and/or parsed.

Because of that, you can’t do this and hope it works:

parseInt('1_000', 10); //-> 1

More information.

And neither is this:

Number('1_000'); //-> NaN

In theory, the builder Number tries to "convert" a value to the numeric type. But Javascript does not understand strings with the numeric separator as valid numbers. That’s why NaN is returned in the expression below:

10_000 - '10_000'; //-> `NaN`
  • The expression above evaluates to NaN because the operator - tries to convert the two operands to the numeric type (if they are not). Internally, an algorithm similar to the constructor Number is used. In this way, as Number('10_000') is NaN, 10_000 - NaN can only be NaN. More details here.
  • Works in the other example of the question (10_000 - '10000') because Javascript can convert the string 10000 to number. Already the string '10_000', as we have seen above, it is not "understood" by the conversion algorithm - thank goodness.

In short, understand the proposal of numerical separators, which today is already part of the language, as something exclusive for the aspect of the code, that is, its syntax. It is not something that brought no "change" too deep...

5

It is something new in JS and should be part of ES2021 already being supported by some Engines. See the numerical separator proposal (Numeric separator).

It is a way to give more readability to numeric literals. So you can use the symbol of underscore in any parts of a number to "group" digits. In general it will be used as a thousand separator or in some cases more specific, even when it uses hexadecimal and mainly binary can be very useful to separate parts of the information. It’s just for this very reason.

The character is completely ignored after compiled. It just makes no sense to use where it does not separate parts of the number, like the beginning, end and it repeated..

let budget = 1_000_000_000_000;
let nibbles = 0b1010_0001_1000_0101;
let message = 0xA0_B0_C0;

Browser other questions tagged

You are not signed in. Login or sign up in order to post.