renovations
This commit is contained in:
parent
4b8b168fd2
commit
c7d4c7e3ff
172 changed files with 869 additions and 244 deletions
|
@ -80,7 +80,7 @@ alert( 1e500 ); // Infinity
|
|||
|
||||
Если математическая операция не может быть совершена, то возвращается специальное значение `NaN` (Not-A-Number).
|
||||
|
||||
Например, деление `0/0` в математическом смысле неопределено, поэтому возвращает `NaN`:
|
||||
Например, деление `0/0` в математическом смысле неопределено, поэтому его результат `NaN`:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -111,7 +111,7 @@ alert( isNaN(n) ); // true
|
|||
```
|
||||
|
||||
[smart]
|
||||
Отсюда вытекает забавный способ проверки значения на `NaN`: можно проверить его на равенство самому себе, вот так:
|
||||
Отсюда вытекает забавный способ проверки значения на `NaN`: можно проверить значение на равенство самому себе, если не равно -- то `NaN`:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -136,15 +136,31 @@ alert( NaN + 1 ); // NaN
|
|||
Если аргумент `isNaN` -- не число, то он автоматически преобразуется к числу.
|
||||
|
||||
|
||||
[summary]Никакие математические операции в JavaScript не могут привести к ошибке или "обрушить" программу.
|
||||
[smart header="Математические операции в JS безопасны"]
|
||||
Никакие математические операции в JavaScript не могут привести к ошибке или "обрушить" программу.
|
||||
|
||||
В худшем случае, результат будет `NaN`.
|
||||
[/summary]
|
||||
[/smart]
|
||||
|
||||
## isFinite(n)
|
||||
|
||||
Итак, в JavaScript есть обычные числа и три специальных числовых значения: `NaN`, `Infinity` и `-Infinity`.
|
||||
|
||||
Тот факт, что они, хоть и особые, но -- числа, демонстрируется работой оператора `+`:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var value = prompt("Введите Infinity", 'Infinity');
|
||||
|
||||
*!*
|
||||
var number = +value;
|
||||
*/!*
|
||||
|
||||
alert(number); // Infinity, плюс преобразовал строку "Infinity" к такому "числу"
|
||||
```
|
||||
|
||||
Обычно если мы хотим от посетителя получить число, то `Infinity` или `NaN` нам не подходят. Для того, чтобы отличить "обычные" числа от таких специальных значений, существует функция `isFinite`.
|
||||
|
||||
**Функция `isFinite(n)` возвращает `true` только тогда, когда `n` -- обычное число, а не одно из этих значений:**
|
||||
|
||||
```js
|
||||
|
@ -154,12 +170,11 @@ alert( isFinite(Infinity) ); // false
|
|||
alert( isFinite(NaN) ); // false
|
||||
```
|
||||
|
||||
Если аргумент `isFinite` -- не число, то он автоматически преобразуется к числу.
|
||||
|
||||
|
||||
## Преобразование к числу
|
||||
|
||||
Строгое преобразование можно осуществить унарным плюсом `'+'`:
|
||||
Большинство арифметических операций и математических функций преобразуют значение в число автоматически.
|
||||
|
||||
Для того, чтобы сделать это явно, обычно перед значением ставят унарный плюс `'+'`:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -167,7 +182,7 @@ var s = "12.34";
|
|||
alert( +s ); // 12.34
|
||||
```
|
||||
|
||||
*Строгое* -- означает, что если строка не является в точности числом, то результат будет `NaN`:
|
||||
При этом, если строка не является в точности числом, то результат будет `NaN`:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -191,38 +206,6 @@ alert( +"1 2" ); // NaN, пробел посередине числа - ошиб
|
|||
alert( '12.34' / "-2" ); // -6.17
|
||||
```
|
||||
|
||||
### isNaN -- проверка на число для строк
|
||||
|
||||
Функция `isNaN` является математической, она преобразует аргумент в число, а затем проверяет, `NaN` это или нет.
|
||||
|
||||
Поэтому можно использовать ее для проверки:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var x = "-11.5";
|
||||
if (isNaN(x)) {
|
||||
alert("Строка преобразовалась в NaN. Не число");
|
||||
} else {
|
||||
alert("Число");
|
||||
}
|
||||
```
|
||||
|
||||
Единственный тонкий момент -- в том, что пустая строка и строка из пробельных символов преобразуются к `0`:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
alert(isNaN(" \n\n ")) // false, т.к. строка из пробелов преобразуется к 0
|
||||
```
|
||||
|
||||
В случае, если применить такую проверку не к строке, то могут быть сюрпризы, в частности `isNaN` посчитает числами значения `false, true, null`, так как они хотя и не числа, но преобразуются к ним:
|
||||
|
||||
```js
|
||||
+false = 0 // isNaN(false) преобразует false в число, получится 0 - ок
|
||||
+true = 1 // тоже ок
|
||||
+null = 0 // тоже ок
|
||||
+undefined = NaN; // а вот это точно не число
|
||||
```
|
||||
|
||||
## Мягкое преобразование: parseInt и parseFloat
|
||||
|
||||
В мире HTML/CSS многие значения не являются в точности числами. Например, метрики CSS: `10pt` или `-12px`.
|
||||
|
@ -241,9 +224,9 @@ alert( +"12px" ) // NaN
|
|||
alert( parseInt('12px') ); // 12
|
||||
```
|
||||
|
||||
**`parseInt` и ее аналог `parseFloat` преобразуют строку символ за символом, пока это возможно.**
|
||||
**Функция `parseInt` и ее аналог `parseFloat` преобразуют строку символ за символом, пока это возможно.**
|
||||
|
||||
При возникновении ошибки возвращается число, которое получилось. `parseInt` читает из строки целое число, а `parseFloat` -- дробное.
|
||||
При возникновении ошибки возвращается число, которое получилось. Функция `parseInt` читает из строки целое число, а `parseFloat` -- дробное.
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -258,34 +241,39 @@ alert( parseFloat('12.3.4') ) // 12.3, ошибка на второй точке
|
|||
alert( parseInt('a123') ); // NaN
|
||||
```
|
||||
|
||||
[warn header="Ошибка `parseInt('0..')`"]
|
||||
|
||||
`parseInt` (но не `parseFloat`) понимает 16-ричную систему счисления:
|
||||
## Проверка на число
|
||||
|
||||
Для проверки строки на число можно использовать функцию `isNaN(str)`.
|
||||
|
||||
Она преобразует строку в число аналогично `+`, а затем вернёт `true`, если это `NaN`, т.е. если преобразование не удалось:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
alert( parseInt('0xFF') ) // 255
|
||||
var x = prompt("Введите значение", "-11.5");
|
||||
|
||||
if (isNaN(x)) {
|
||||
alert("Строка преобразовалась в NaN. Не число");
|
||||
} else {
|
||||
alert("Число");
|
||||
}
|
||||
```
|
||||
|
||||
В старом стандарте JavaScript он умел понимать и восьмеричную:
|
||||
Однако, у такой проверки есть две особенности:
|
||||
|
||||
<ol><li>Пустая строка и строка из пробельных символов преобразуются к `0`, поэтому считаются числами.</li>
|
||||
<li>Если применить такую проверку не к строке, то могут быть сюрпризы, в частности `isNaN` посчитает числами значения `false, true, null`, так как они хотя и не числа, но преобразуются к ним.</li>
|
||||
</ol>
|
||||
|
||||
```js
|
||||
//+ run
|
||||
alert( parseInt('010') ) // в некоторых браузерах 8
|
||||
alert( isNaN(null) ); // false - не NaN, т.е. "число"
|
||||
alert( isNaN("\n \n") ); // false - не NaN, т.е. "число"
|
||||
```
|
||||
|
||||
Если вы хотите быть уверенным, что число, начинающееся с нуля, будет интерпретировано верно -- используйте второй необязательный аргумент `parseInt` -- основание системы счисления:
|
||||
Если такое поведение допустимо, то `isNaN` -- приемлемый вариант.
|
||||
|
||||
```js
|
||||
//+ run
|
||||
alert( parseInt('010', 10) ); // во всех браузерах 10
|
||||
```
|
||||
|
||||
[/warn]
|
||||
|
||||
## Проверка на число для всех типов
|
||||
|
||||
Если вам нужна действительно точная проверка на число, которая не считает числом строку из пробелов, логические и специальные значения -- используйте следующую функцию `isNumeric`:
|
||||
Если же нужна действительно точная проверка на число, которая не считает числом строку из пробелов, логические и специальные значения, а также отсекает `Infinity` -- используйте следующую функцию `isNumeric`:
|
||||
|
||||
```js
|
||||
function isNumeric(n) {
|
||||
|
@ -318,10 +306,12 @@ var n = 255;
|
|||
alert( n.toString(16) ); // ff
|
||||
```
|
||||
|
||||
В частности, это используют для работы с цветовыми значениями в браузере, вида `#AABBCC`.
|
||||
|
||||
Основание может быть любым от `2` до `36`.
|
||||
|
||||
<ul>
|
||||
<li>Основание `2` бывает полезно для отладки битовых операций, которые мы пройдём чуть позже:
|
||||
<li>Основание `2` бывает полезно для отладки побитовых операций:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -338,7 +328,7 @@ var n = 1234567890;
|
|||
alert( n.toString(36) ); // kf12oi
|
||||
```
|
||||
|
||||
При помощи такого кодирования можно сделать длинный цифровой идентификатор короче, чтобы затем использовать его в URL.
|
||||
При помощи такого кодирования можно "укоротить" длинный цифровой идентификатор, например чтобы выдать его в качестве URL.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
@ -386,14 +376,14 @@ alert( 1.2 + 1.3 ^ 0); // 2, приоритет ^ меньше, чем +
|
|||
Это удобно в первую очередь тем, что легко читается и не заставляет ставить дополнительные скобки как `Math.floor(...)`:
|
||||
|
||||
```js
|
||||
var x = a * b / c ^ 0; // читается так: "a*b/c *!*и округлить*/!*"
|
||||
var x = a * b / c ^ 0; // читается как "a * b / c и округлить"
|
||||
```
|
||||
|
||||
[/smart]
|
||||
|
||||
### Округление до заданной точности
|
||||
|
||||
Обычный трюк -- это умножить и поделить на 10 с нужным количеством нулей. Например, округлим `3.456` до 2го знака после запятой:
|
||||
Для округления до нужной цифры после запятой можно умножить и поделить на 10 с нужным количеством нулей. Например, округлим `3.456` до 2го знака после запятой:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -405,7 +395,7 @@ alert( Math.round( n * 100 ) / 100 ); // 3.456 -> 345.6 -> 346 -> 3.46
|
|||
|
||||
### num.toFixed(precision)
|
||||
|
||||
Существует специальный метод `num.toFixed(precision)`, который округляет число `num` до точности `precision` и возвращает результат *в виде строки*:
|
||||
Существует также специальный метод `num.toFixed(precision)`, который округляет число `num` до точности `precision` и возвращает результат *в виде строки*:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -438,14 +428,14 @@ alert( +n.toFixed(5) ); // 12.34
|
|||
```
|
||||
|
||||
[warn header="Метод `toFixed` не эквивалентен `Math.round`!"]
|
||||
Например, произведём округление до одного знака после запятой с использованием двух способов:
|
||||
Например, произведём округление до одного знака после запятой с использованием двух способов: `toFixed` и `Math.round` с умножением и делением:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var price = 6.35;
|
||||
|
||||
alert( price.toFixed(1) ); // 6.3
|
||||
alert( Math.round(price*10)/10 ); // 6.4
|
||||
alert( Math.round(price * 10) / 10 ); // 6.4
|
||||
```
|
||||
|
||||
Как видно, результат разный! Вариант округления через `Math.round` получился более корректным, так как по общепринятым правилам `5` округляется вверх. А `toFixed` может округлить его как вверх, так и вниз. Почему? Скоро узнаем!
|
||||
|
@ -463,7 +453,7 @@ alert(0.1 + 0.2 == 0.3);
|
|||
|
||||
Запустили? Если нет -- все же сделайте это.
|
||||
|
||||
Ок, вы запустили его. Результат несколько странный, не так ли? Возможно, ошибка в браузере? Поменяйте браузер, запустите еще раз.
|
||||
Ок, вы запустили его. Он вывел `false`. Результат несколько странный, не так ли? Возможно, ошибка в браузере? Поменяйте браузер, запустите еще раз.
|
||||
|
||||
Хорошо, теперь мы можем быть уверены: `0.1 + 0.2` это не `0.3`. Но тогда что же это?
|
||||
|
||||
|
@ -472,20 +462,25 @@ alert(0.1 + 0.2 == 0.3);
|
|||
alert(0.1 + 0.2); // 0.30000000000000004
|
||||
```
|
||||
|
||||
Как видите, произошла небольшая вычислительная ошибка.
|
||||
Как видите, произошла небольшая вычислительная ошибка, результат сложения `0.1 + 0.2` немного больше, чем `0.3`.
|
||||
|
||||
Дело в том, что в стандарте IEEE 754 на число выделяется ровно 8 байт(=64 бита), не больше и не меньше.
|
||||
```js
|
||||
//+ run
|
||||
alert(0.1 + 0.2 > 0.3); // true
|
||||
```
|
||||
|
||||
Число `0.1 (=1/10)` короткое в десятичном формате, а в двоичной системе счисления это бесконечная дробь ([перевод десятичной дроби в двоичную систему](http://www.klgtu.ru/students/literature/inf_asu/1760.html)). Также бесконечной дробью является `0.2 (=2/10)`.
|
||||
Всё дело в том, что в стандарте IEEE 754 на число выделяется ровно 8 байт(=64 бита), не больше и не меньше.
|
||||
|
||||
Двоичное значение бесконечных дробей хранится только до определенного знака, поэтому возникает неточность. Это даже можно увидеть:
|
||||
Число `0.1 (одна десятая)` записывается просто в десятичном формате, а в двоичной системе счисления это бесконечная дробь ([перевод десятичной дроби в двоичную систему](http://www.klgtu.ru/students/literature/inf_asu/1760.html)). Также бесконечной дробью является `0.2 (=2/10)`.
|
||||
|
||||
Двоичное значение бесконечных дробей хранится только до определенного знака, поэтому возникает неточность. Её даже можно увидеть:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
alert( 0.1.toFixed(20) ); // 0.10000000000000000555
|
||||
```
|
||||
|
||||
Когда мы складываем `0.1` и `0.2`, то две неточности складываются, получаем третью.
|
||||
Когда мы складываем `0.1` и `0.2`, то две неточности складываются, получаем незначительную, но всё же ошибку в вычислениях.
|
||||
|
||||
Конечно, это не означает, что точные вычисления для таких чисел невозможны. Они возможны. И даже необходимы.
|
||||
|
||||
|
@ -518,7 +513,7 @@ alert( +result.toFixed(10) ); // 0.3
|
|||
|
||||
```js
|
||||
//+ run
|
||||
alert(9999999999999999);
|
||||
alert(9999999999999999); // выведет 10000000000000000
|
||||
```
|
||||
|
||||
Причина та же -- потеря точности.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue