Since the introduction of modern JavaScript with ES5 and later ES6, common language patterns and structures were introduced that lifted the limited expressive power of the original JavaScript language to the level of more robust programming languages.
In the first part of this blog post, I touched on Map
and Set
, in the second part I discussed iterators and collections. In the third part, I will take a look at what seems a basic data type: numbers.
Numerical Precision
Numerical values are represented in JavaScript by the Number type, which is used for both integer and floating point data. Since the early days of JavaScript, numbers have been a source of confusion and common error, because behaviour depends on low-level binary floating point implementation details.
Because of the binary nature of computers, floating point values are combinations of powers of 2, which means they are often only an approximation of decimal fractions. For example, if you want to check if 2 numbers add up to a value:
let a = 0.1
let b = 0.2
let c = 0.3
a + b === c // false!
Because these numbers are internally represented as a binary floating point value, in this case there is a tiny fraction of a difference. In fact the result of '0.1 + 0.2' is actually more like 0.30000000000000004.
To make sure numbers are 'equal', or, to be more precise, the difference between numbers is 0, you actually need to check if the difference is smaller than the smallest representable difference.
In ES6, a new constant was introduced, Number.EPSILON
, which is equal to 2^-52 and can be thought of as the margin of error between the decimal number and its binary floating point representation.
So, to correctly compare numbers, the above example would need to be:
let a = 0.1
let b = 0.2
let c = 0.3
a + b - c < Number.EPSILON // true!
This is also useful when correctly rounding numbers to fixed decimal precision:
let price = 5.015
Math.round(price * 100) / 100 // 5.01
Math.round(price * 100 * (1 + Number.EPSILON)) / 100 // 5.02
Number Validity Checking
ES6 introduced 2 useful methods.
The first one is isNaN
, which is used to check if a value is a valid number:
Number.isNaN(42) // false
Number.isNaN('42') // false
Number.isNaN('fortytwo') // true
Number.isNaN(Math.sqrt(-1)) // true
Number.isNaN(NaN) // true
The second one is to see if a number is finite or infinite:
Number.isFinite(42) // true
Number.isFinite(2 / 0) // false
Number.isFinite(Infinity) // false
Number.isFinite(NaN) // false
Number Formatting
Although numbers are mostly used internally in code to perform arithmetic on data, eventually there will be a visual display of the result. The way numbers are formatted differs between countries and cultures, so localization needs to be applied before they are actually displayed.
ES6 introduced the Intl
module, which takes care of digit grouping and separators:
let localeUS = new Intl.NumberFormat('en-US')
let localeNL = new Intl.NumberFormat('nl-NL')
let data = 12345.678
localeUS.format(data) // 12,345.678
localeNL.format(data) // 12.345,678
Also, since numerical data is often related to monetary values, the Intl
module also allows for the correct display of currencies:
var localeUS = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" })
var localeNL = new Intl.NumberFormat("nl-NL", { style: "currency", currency: "EUR" })
var localeFR = new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR" })
let data = 42000.42
localeUS.format(data) // $42,000.42
localeNL.format(data) // € 42.000,42
localeFR.format(data) // 42 000,42 €
Conclusion
Dealing with numbers is a challenge in any programming language, but especially so in JavaScript since it only has a very bare-bones Number data type. The examples above show you how to prevent common errors and how to simplify the visualization of numeric data in any language out of the box!
As always, we hope you liked this article and if you have anything to add, maybe you are suited for a Developer position in Notificare. We are currently looking for a Core API Developer, check out the job description. If modern Javascript is your thing, don't hesitate to apply!