Proposal: a more consistent and stricter number converting function - Number.of()

# 段垚 (7 years ago)

Converting an arbitray value to a number in JS can be rather inconsistent and unexpected:

  • null and undefined are different: +null === 0 but +undefined is NaN.

  • Empty string and non-nubmeric strings are different: +"" === 0 but +"foo" is NaN.

This problem can be worse because JSON only support finite numbers:


var total = 0;

total += JSON.parse(JSON.stringify({ "value": 0/0 })).value;

total === 0; //Oops, NaN is serialized as null, and then converted to 0

So I propose a more consistent and stricter number converting function: Number.of(value):

  1. If value is null or undefined, return NaN;

  2. If value is a number, return value itself;

  3. If value.valueOf() returns a number, return that number, otherwise return NaN.

This means all non-number values except those have number type .valueOf() would be converted to NaN:


Number.of(null); // NaN

Number.of(''); //NaN

Number.of('1'); //NaN


var total = 0;

total += Number.of(JSON.parse(JSON.stringify({ "value": 0/0 })).value);

total; // NaN

What do you think?

,

Duan, Yao

# Claude Pache (7 years ago)

Le 24 févr. 2017 à 04:50, 段垚 <duanyao at ustc.edu> a écrit :

Hi,

Converting an arbitray value to a number in JS can be rather inconsistent and unexpected:

  • null and undefined are different: +null === 0 but +undefined is NaN.

  • Empty string and non-nubmeric strings are different: +"" === 0 but +"foo" is NaN.

This problem can be worse because JSON only support finite numbers:


var total = 0;

total += JSON.parse(JSON.stringify({ "value": 0/0 })).value;

total === 0; //Oops, NaN is serialized as null, and then converted to 0

So I propose a more consistent and stricter number converting function: Number.of(value):

  1. If value is null or undefined, return NaN;

  2. If value is a number, return value itself;

  3. If value.valueOf() returns a number, return that number, otherwise return NaN.

This means all non-number values except those have number type .valueOf() would be converted to NaN:


Number.of(null); // NaN

Number.of(''); //NaN

Number.of('1'); //NaN


var total = 0;

total += Number.of(JSON.parse(JSON.stringify({ "value": 0/0 })).value);

total; // NaN

What do you think?

,

Duan, Yao

Depending on the concrete situation, you might not need yet another way to convert into number.

  • If you know that your input is either a string or null/undefined (e.g., as the result of someHTMLElement.getAttribute('foo')), you could use Number.parseFloat(), which will produce NaN for the empty string, null and undefined.

  • If your issue is precisely with null/undefined, as it is the case in your JSON example, a more generic solution would be the null-coalescing operator ??, which allows to express more precisely and more clearly what you mean. The semantics is:

a ?? b // evaluates `a`. If `a` is null or undefined, evaluates `b`.

In your JSON example:

var total = 0;

total += JSON.parse(JSON.stringify({ "value": 0/0 })).value ?? NaN;

Number.isNaN(total); // true. Hurray!
# T.J. Crowder (7 years ago)
  • If you know that your input is either a string or null/undefined (e.g., as the result of someHTMLElement.getAttribute('foo')), you could use Number.parseFloat(), which will produce NaN for the empty string, null and undefined.

Of course, Number.parseFloat("23.4ducky") results in 23.4. Duan indicated he/she wanted this Number.of to be more strict.

I, too, have wanted something strict that didn't convert "" and null to 0. (Like many, I suspect, I have one in my toolkit; but the idea of something in the standard library appeals.)

-- T.J.

# 段垚 (7 years ago)

在 2017/2/24 20:08, Claude Pache 写道:

Le 24 févr. 2017 à 04:50, 段垚 <duanyao at ustc.edu> a écrit :

Hi,

Converting an arbitray value to a number in JS can be rather inconsistent and unexpected:

  • null and undefined are different: +null === 0 but +undefined is NaN.

  • Empty string and non-nubmeric strings are different: +"" === 0 but +"foo" is NaN.

This problem can be worse because JSON only support finite numbers:


var total = 0;

total += JSON.parse(JSON.stringify({ "value": 0/0 })).value;

total === 0; //Oops, NaN is serialized as null, and then converted to 0

So I propose a more consistent and stricter number converting function: Number.of(value):

  1. If value is null or undefined, return NaN;

  2. If value is a number, return value itself;

  3. If value.valueOf() returns a number, return that number, otherwise return NaN.

This means all non-number values except those have number type .valueOf() would be converted to NaN:


Number.of(null); // NaN

Number.of(''); //NaN

Number.of('1'); //NaN


var total = 0;

total += Number.of(JSON.parse(JSON.stringify({ "value": 0/0 })).value);

total; // NaN

What do you think?

,

Duan, Yao

Depending on the concrete situation, you might not need yet another way to convert into number.

  • If you know that your input is either a string or null/undefined (e.g., as the result of someHTMLElement.getAttribute('foo')), you could use Number.parseFloat(), which will produce NaN for the empty string, null and undefined.

What I actually want is a function/operator that protect against non-number values, including strings that can be parsed as numbers, and objects whose .toString() happen to return strings can be parsed as numbers.

  • If your issue is precisely with null/undefined, as it is the case in your JSON example, a more generic solution would be the null-coalescing operator ??, which allows to express more precisely and more clearly what you mean. The semantics is:
a ?? b // evaluates `a`. If `a` is null or undefined, evaluates `b`.

In your JSON example:

var total = 0;

total += JSON.parse(JSON.stringify({ "value": 0/0 })).value ?? NaN;

Number.isNaN(total); // true. Hurray!

The null-coalescing operator ?? is awosome and will solve my null/undefined issue. However, it seems there is little progress since it was proposed ( esdiscuss.org/topic/proposal-for-a-null-coalescing-operator ). Are there objections or simply lack of interest?

# Isiah Meadows (7 years ago)

Most likely lack of interest and nobody trying to push it through the process. It's come up repeatedly, but no one has actually tried to write up a formal proposal and get someone on TC39 to champion it.

Isiah Meadows me at isiahmeadows.com