renovations

This commit is contained in:
Ilya Kantor 2015-01-11 01:54:57 +03:00
parent 4b8b168fd2
commit c7d4c7e3ff
172 changed files with 869 additions and 244 deletions

View file

@ -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
```
Причина та же -- потеря точности.