You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The JavaScript language steadily evolves. The new proposals get analyzed and, if they look worthy, are appended to the list at <https://tc39.github.io/ecma262/> and then progress to the [specification](http://www.ecma-international.org/publications/standards/Ecma-262.htm).
5
+
6
+
Each JS engine has its own idea about what to implement first. It may implement proposals that are not approved yet and fail to implement things that are already in the spec, because they are less interesting or just harder to do.
7
+
8
+
So it's quite common for an engine to implement only the part of the standard.
9
+
10
+
A good page to see the current state of support for language features is <https://kangax.github.io/compat-table/es6/> (remember the link to use in the future when you know the language).
11
+
12
+
## Babel.JS
13
+
14
+
When we use all the modern features of the language, some engines may fail to support such code. Just as it was said, not all features are implemented everywhere.
15
+
16
+
Here Babel.JS comes to the rescue.
17
+
18
+
[Babel.JS](https://babeljs.io) is a [transpiler](https://en.wikipedia.org/wiki/Source-to-source_compiler). It rewrites the modern JavaScript code into the previous standard.
19
+
20
+
Actually, there are two parts in Babel:
21
+
22
+
1. The transpiler program, which rewrites the code.
23
+
24
+
The transpiler runs on a developer's computer. It rewrites the code, which is then bundled by a project build system (like [webpack](http://webpack.github.io/) or [brunch](http://brunch.io/)). Most build systems can support Babel easily.
25
+
26
+
2. The polyfill.
27
+
28
+
For some functions we also need add a special script that should run before our scripts and introduce modern functions that the engine may not support by itself. There's a term "polyfill" for such scripts.
29
+
30
+
The two interesting variants are [babel polyfill](https://babeljs.io/docs/usage/polyfill/) that supports a lot, but is big and the [polyfill.io](http://polyfill.io) service that allows to load/construct polyfills on-demand, depending on the features we need.
31
+
32
+
The transpiler and/or polyfill may be not needed if we orient towards more-or-less modern engines and don't use rarely supported features.
33
+
34
+
## Examples in the tutorial
35
+
36
+
```warn header="Browser support is required"
37
+
Examples that use modern JS will work only if your browser supports it.
38
+
```
39
+
40
+
````online
41
+
Most examples are runnable at-place, like here:
42
+
43
+
```js run
44
+
alert('Press the "Play" button in the upper-right corner to run');
45
+
```
46
+
47
+
...But if it uses a feature that your browser does not support, an error is shown.
48
+
49
+
That doesn't mean that the example is wrong! It's just the browser lacking the support for certain features yet.
50
+
````
51
+
52
+
[Chrome Canary](https://www.google.com/chrome/browser/canary.html) is good for more examples.
53
+
54
+
Note that on production we can use Babel to translate the code into suitable for less recent browsers, so there will be no such limitation, the code will run everywhere.
55
+
56
+
Now we can go coding, so let's choose a good code editor.
Copy file name to clipboardExpand all lines: 1-js/4-data-structures/2-number/article.md
+53-77Lines changed: 53 additions & 77 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ All numbers in JavaScript are stored in 64-bit format [IEEE-754](http://en.wikip
4
4
5
5
Let's recap what we know about them and add a little bit more.
6
6
7
-
## Advanced ways to write
7
+
## More ways to write a number
8
8
9
9
Imagine, we need to write a billion. The obvious way is:
10
10
@@ -54,18 +54,19 @@ In other words, a negative number after `e` means a division by 1 with the given
54
54
1.23e-6=1.23/1000000 (=0.00000123)
55
55
```
56
56
57
-
## Hex, binary and octal numbers
57
+
###Hex, binary and octal numbers
58
58
59
-
Hexadecimal numbers are widely used in JavaScript: to represent colors, encode characters and for many other things. So there exists a short way to write them: `0x` and then the number.
59
+
[Hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) numbers are widely used in JavaScript: to represent colors, encode characters and for many other things. So there exists a short way to write them: `0x` and then the number.
60
60
61
61
For instance:
62
62
63
63
```js run
64
64
alert( 0xff ); // 255
65
-
alert( 0xFF ); // the same, letters can be uppercased, doesn't matter
65
+
alert( 0xFF ); //255 (the same, case doesn't matter)
66
66
```
67
67
68
-
Binary and octal numeral systems are rarely used, but also possible to write them right way:
68
+
Binary and octal numeral systems are rarely used, but also supported using `0b` and `0o` prefixes:
69
+
69
70
70
71
```js run
71
72
let a =0b11111111; // binary form of 255
@@ -74,38 +75,36 @@ let b = 0o377; // octal form of 255
74
75
alert( a == b ); // true, the same number 255 at both sides
75
76
```
76
77
77
-
So as you can see, we prepend the number with `0x` for a hex, `0b` for a binary and `0o` for an octal.
78
+
There are only 3 numeral systems with such support. For other numeral systems we should use function `parseInt` (goes later in this chapter).
78
79
79
80
## toString(base)
80
81
81
-
There is also a "reverse" method `num.toString(base)`that returns a string representation of `num` in the given `base`.
82
+
There method `num.toString(base)` returns a string representation of `num` in the numeral system with the given `base`.
82
83
83
84
For example:
84
85
```js run
85
86
let num =255;
86
87
87
-
alert( num.toString(2) ); //11111111
88
-
alert( num.toString(8) ); //377
88
+
alert( num.toString(16) ); //ff
89
+
alert( num.toString(2) ); //11111111
89
90
```
90
91
91
92
The `base` can vary from `2` to `36`.
92
93
93
94
Most often use cases are:
94
95
95
-
-**16**, because hexadecimal numeral system is used for colors, character encodings etc, digits can be `0..9` or `A..F`.
96
-
-**2** is mostly for debugging bitwise operations, digits can be only `0` or `1`.
97
-
-**36** is the maximum, digits can be `0..9` or `A..Z`. The whole latin alphabet is used to represent a number.
98
-
99
-
A funny, but useful case for `36` is when we need to turn a long numeric identifier into something shorter, for example to make a short url. The base-36 notation is an easy way to go:
96
+
-**base=16** is used for colors, character encodings etc, digits can be `0..9` or `A..F`.
97
+
-**base=2** is mostly for debugging bitwise operations, digits can be `0` or `1`.
98
+
-**base=36** is the maximum, digits can be `0..9` or `A..Z`. The whole latin alphabet is used to represent a number. A funny, but useful case for `36` is when we need to turn a long numeric identifier into something shorter, for example to make a short url. Can simply represent it in the numeral system with base `36`:
100
99
101
-
```js run
102
-
alert( 123456..toString(36) ); // 2n9c
103
-
```
100
+
```js run
101
+
alert( 123456..toString(36) ); // 2n9c
102
+
```
104
103
105
104
```warn header="Two dots to call a method"
106
-
If we want to call a method directly on a number, like `toString` in the example above, then we need to place two dots `..` after it.
105
+
Please note that two dots in `123456..toString(36)` is not a typo. If we want to call a method directly on a number, like `toString` in the example above, then we need to place two dots `..` after it.
107
106
108
-
If we place a single dot: `123456.toString(36)`, then there will be an error, because JavaScript awaits the decimal part after the dot. And if we place one more dot, then JavaScript knows that the number has finished and we mean the method.
107
+
If we placed a single dot: `123456.toString(36)`, then there would be an error, because JavaScript syntax implies the decimal part after the first dot. And if we place one more dot, then JavaScript knows that the decimal part is empty and now goes the method.
109
108
```
110
109
111
110
## Rounding
@@ -126,22 +125,17 @@ There are following built-in functions for rounding:
126
125
`Math.trunc` (not supported by Internet Explorer)
127
126
: Removes the decimal part:`3.1` becomes `3`, `-1.1` becomes `-1`.
128
127
128
+
Here's the table to summarize the differences between them:
These functions cover all possible ways to deal with the decimal part.
143
-
144
-
But what if we'd like to round the number to `n-th` digit after the point?
138
+
These functions cover all possible ways to deal with the decimal part as a whole. But what if we'd like to round the number to `n-th` digit after the point?
145
139
146
140
For instance, we have `1.2345` and want to round it to 2 digits, getting only `1.23`.
147
141
@@ -170,77 +164,66 @@ There are two ways to do so.
170
164
alert( num.toFixed(1) ); // "12.4"
171
165
```
172
166
173
-
The resulting string is zero-padded to the required precision if needed:
167
+
Please note that result of `toFixed` is a string. If the decimal part is shorter than required, zeroes are appended to its end:
174
168
175
169
```js run
176
170
let num = 12.34;
177
171
alert( num.toFixed(5) ); // "12.34000", added zeroes to make exactly 5 digits
178
172
```
179
173
180
-
Let's note once again that the result is a string. We can convert it to a number using the unary plus or a `Number()` call.
174
+
We can convert it to a number using the unary plus or a `Number()` call: `+num.toFixed(5)`.
181
175
182
176
## Imprecise calculations
183
177
184
-
Internally, each number occupies 64 bits, 52 of them are used to store the digits, 11 of them store the location of the point (to allow fractions) and 1 is the sign.
178
+
Internally, a number is represented in 64-bit format [IEEE-754](http://en.wikipedia.org/wiki/IEEE_754-1985). So, there are exactly 64 bits to store a number: 52 of them are used to store the digits, 11 of them store the position of the decimal point (they are zero for integer numbers) and 1 bit for the sign.
185
179
186
-
If a number is too big, it would overflow the storage, potentially giving an infinity:
180
+
If a number is too big, it would overflow the 64-bit storage, potentially giving an infinity:
187
181
188
182
```js run
189
183
alert( 1e500 ); // Infinity
190
184
```
191
185
192
-
But what happens much more often is the loss of precision.
186
+
But what may be a little bit more obvious, but happens much often is the loss of precision.
193
187
194
-
Consider this:
188
+
Consider this (falsy!) test:
195
189
196
190
```js run
197
191
alert( 0.1 + 0.2 == 0.3 ); // *!*false*/!*
198
192
```
199
193
200
-
Yes, you got that right, the sum of `0.1` and `0.2` is not `0.3`. What is it then?
194
+
Yes, indeed, if we check whether the sum of `0.1` and `0.2` is `0.3`, we get `false`.
195
+
196
+
Strange! What is it then if not `0.3`?
201
197
202
198
```js run
203
199
alert( 0.1 + 0.2 ); // 0.30000000000000004
204
200
```
205
201
206
-
Imagine you're making an e-shopping site and the visitor puts `$0.10` and `$0.20` goods into his chart. The order total will be `$0.30000000000000004`. That would surprise anyone.
202
+
Ouch! There are more consequences than an incorrect comparison here. Imagine you're making an e-shopping site and the visitor puts `$0.10` and `$0.20` goods into his chart. The order total will be `$0.30000000000000004`. That would surprise anyone.
207
203
208
204
Why does it work like that?
209
205
210
-
A number is stored in memory in it's binary form, as a sequence of ones and zeroes. But decimal fractions like `0.1`, `0.2` are actually unending fractions in their binary form.
206
+
A number is stored in memory in it's binary form, as a sequence of ones and zeroes. But fractions like `0.1`, `0.2` that look simple in the decimal numeric system are actually unending fractions in their binary form.
211
207
212
-
In other words, what is `0.1`? It is one divided by ten.
208
+
In other words, what is `0.1`? It is one divided by ten `1/10`, one-tenth. In decimal numeral system such numbers are easily representable. Compare it to one-third: `1/3`. It becomes an endless fraction `0.33333(3)`.
213
209
214
-
But in the binary numeral system, we can only get "clean" division by the powers of two:
210
+
So, division by powers `10` is guaranteed to look well in the decimal system, but the division by `3` is not. For the same reason, in the binary numeral system, the division by powers of `2` is guaranteed to look good, but `1/10` becomes an endless binary fraction.
215
211
216
-
```js
217
-
// binary numbers
218
-
10 = 1 * 2
219
-
100 = 1 * 4
220
-
1000 = 1 * 8
221
-
...
222
-
// now the reverse
223
-
0.1 = 1 / 2
224
-
0.01 = 1 / 4
225
-
0.001 = 1 / 8
226
-
...
227
-
```
212
+
There's just no way to store *exactly 0.1* or *exactly 0.2* in the binary system, just like there is no way to store one-third as a decimal fraction.
228
213
229
-
So, there's just no way to store *exactly 0.1* or *exactly 0.2* as a binary fraction. Just like there is no way to store one-third as a decimal fraction.
230
-
231
-
The numeric format "fixes" that by storing the nearest possible number. There are rounding rules that normally don't allow us to see that "tiny precision loss", but it still exists.
214
+
The numeric format IEEE-754 solves that by storing the nearest possible number. There are rounding rules that normally don't allow us to see that "tiny precision loss", so the number shows up as `0.3`. But the loss still exists.
And when we sum two numbers, then their "precision losses" sum up too.
221
+
And when we sum two numbers, then their "precision losses" sum up.
239
222
240
223
That's why `0.1 + 0.2` is not exactly `0.3`.
241
224
242
225
```smart header="Not only JavaScript"
243
-
The same problem exists in many other programming languages.
226
+
The same issue exists in many other programming languages.
244
227
245
228
PHP, Java, C, Perl, Ruby give exactly the same result, because they are based on the same numeric format.
246
229
```
@@ -267,14 +250,15 @@ Can we work around the problem? Sure, there's a number of ways:
267
250
alert( (0.1*10 + 0.2*10) / 10 ); // 0.3
268
251
```
269
252
270
-
It works, because `0.1*10 = 1` and `0.2 * 10 = 2`are integers. The rounding rules of the format fix the precision loss in the processofmultiplication. Now the resulting integer numbers can now be exactly represented in the binary format.
253
+
It works, because when we get `0.1*10 = 1` and `0.2 * 10 = 2` then both numbers are integers, there's no precision loss for them.
271
254
272
255
3. If it's a shop, then the most radical solution would be to store all prices in cents. No fractions at all. But what if we apply a discount of 30%? In practice, totally evading fractions is rarely feasible, so the solutions listed above are here to help.
@@ -283,31 +267,24 @@ The reason is the same: loss of precision. There are 64 bits for the number, 52
283
267
JavaScript doesn't trigger an error in such case. It does the best to fit the number into the format. Unfortunately, the format is not big enough.
284
268
````
285
269
286
-
## parseInt and parseFloat
287
-
288
-
We already know the easiest way to convert a value into a number. It's the unary plus!
289
-
290
-
But in web-programming we sometimes meet values that
291
-
292
-
293
270
## Tests: isFinite and isNaN
294
271
295
-
Remember those two special numeric values?
272
+
Remember the two special numeric values?
296
273
297
274
- `Infinite` (and `-Infinite`) is a special numeric value that is greater (less) than anything.
298
275
- `NaN` represends an error.
299
276
300
-
There are special functions to check for them:
277
+
They belong to the type `number`, but are not "normal" numbers, so there are special functions to check for them:
301
278
302
279
303
-
- `isNaN(value)` converts its argument to a number and then tests if for being `NaN:
280
+
- `isNaN(value)` converts its argument to a number and then tests if for being `NaN`:
304
281
305
282
```js run
306
283
alert( isNaN(NaN) ); // true
307
284
alert( isNaN("str") ); // true
308
285
```
309
286
310
-
But can't we just use `===` here? Funny, but no. The value `NaN` is unique. It does not equal anything including itself:
287
+
But do we need the function? Can we just use the comparison `=== NaN`? Funny, but no. The value `NaN` is unique in that it does not equal anything including itself:
311
288
312
289
```js run
313
290
alert( NaN === NaN ); // false
@@ -327,15 +304,15 @@ Sometimes `isFinite` is used to validate the string value for being a regular nu
327
304
```js run
328
305
let num = +prompt("Enter a number", '');
329
306
330
-
// isFinite will be true only for regular numbers
331
-
alert(`num:${num}, isFinite:${isFinite(num)}`);
307
+
// will be true unless you enter Infinity, -Infinity or not a number
308
+
alert( isFinite(num));
332
309
```
333
310
334
-
Please note that an empty or a space-only string is treated as `0` in the described case. If it's not what's needed, then additional checks are required.
311
+
Please note that an empty or a space-only string is treated as `0` in all numeric functions. If it's not what's needed, then additional checks are required.
335
312
336
313
## parseInt and parseFloat
337
314
338
-
Regular numeric conversion is harsh. If a value is not exactly a number, it fails:
315
+
The numeric conversion using a plus `+` or `Number()` is strict. If a value is not exactly a number, it fails:
339
316
340
317
```js run
341
318
alert( +"100px" ); // NaN
@@ -404,8 +381,7 @@ A few examples:
404
381
alert( Math.pow(2, 10) ); // 2 in power 10 = 1024
405
382
```
406
383
407
-
408
-
You can find the full list of functions in the docs for the [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) object.
384
+
There are more functions and constants in `Math`, including trigonometry, you can find them in the [docs for the Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) object.
409
385
410
386
## Summary
411
387
@@ -427,10 +403,10 @@ For converting values like `12pt` and `100px` to a number:
427
403
For fractions:
428
404
429
405
- Round using `Math.floor`, `Math.ceil`, `Math.trunc`, `Math.round` or `num.toFixed(precision)`.
430
-
- Remember about the loss of precision when comparing or doing maths.
406
+
- Remember about the loss of precision when working with fractions.
431
407
432
-
Mathematical functions:
408
+
More mathematical functions:
433
409
434
-
- See the [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) manual when you need them. The library is very small, but can cover basic needs.
410
+
- See the [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) object when you need them. The library is very small, but can cover basic needs.
0 commit comments