Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык JavaScript часть1.pdf
Скачиваний:
189
Добавлен:
22.03.2016
Размер:
8.92 Mб
Скачать

использовать именно её в проектах.

Открыть песочницу с тестами для задачи.

К решению

Добавьте тест к задаче

важность: 5

Добавьте к предыдущей задаче тесты, которые будут проверять, что любое число, кроме нуля, в нулевой степени равно 1, а ноль в нулевой степени даёт NaN(это математически корректно,

результат 00 не определён).

При необходимости, исправьте реализацию, чтобы тесты проходили без ошибок.

Открыть песочницу с тестами для задачи.

К решению

Что не так в тесте?

важность: 5

Что не так в этом тесте функции pow?

it("Возводит x в степень n", function() { var x = 5;

var result = x; assert.equal(pow(x, 1), result);

var result *= x; assert.equal(pow(x, 2), result);

var result *= x; assert.equal(pow(x, 3), result);

});

P.S. Синтаксически он верен и работает, но спроектирован неправильно.

К решению

Структуры данных

Изучаем JavaScript: расширенное знакомство со встроенными типами данных, их особенностями.

Введение в методы и свойства

Все значения в JavaScript, за исключением nullи undefined, содержат набор вспомогательных функций и значений, доступных «через точку».

Такие функции называют «методами», а значения — «свойствами». Здесь мы рассмотрим основы использования свойств и методов.

Свойство str.length

У строки есть свойство length, содержащее длину:

alert( "Привет, мир!".length ); // 12

Можно и записать строку в переменную, а потом запросить её свойство:

var str = "Привет, мир!"; alert( str.length ); // 12

Метод str.toUpperCase()

Также у строк есть метод toUpperCase(), который возвращает строку в верхнем регистре:

var hello = "Привет, мир!";

alert( hello.toUpperCase() ); // "ПРИВЕТ, МИР!"

Вызов метода — через круглые скобки!

Обратите внимание, для вызова метода обязательно нужны круглые скобки.

Посмотрите, например, результат обращения к toUpperCaseбез скобок:

var hello = "Привет";

alert( hello.toUpperCase ); // function...

Метод — это встроенная команда («функция», мы поговорим о них позже), которую нужно вызвать для получения значения. При обращении без скобок мы получим саму эту функцию. Как правило браузер выведет её как-то так: "function toUpperCase() { ... }".

А чтобы получить результат — нужно произвести её вызов, добавив скобки:

var hello = "Привет";

alert( hello.toUpperCase() ); // ПРИВЕТ

Более подробно с различными свойствами и методами строк мы познакомимся в главе Строки.

Метод num.toFixed(n)

Есть методы и у чисел, например num.toFixed(n). Он округляет число numдо nзнаков после запятой,

при необходимости добивает нулями до данной длины и возвращает в виде строки (удобно для форматированного вывода):

var n = 12.345;

alert( n.toFixed(2) ); // "12.35" alert( n.toFixed(0) ); // "12" alert( n.toFixed(5) ); // "12.34500"

Детали работы toFixedразобраны в главе Числа.

Обращение к методам чисел

К методу числа можно обратиться и напрямую:

alert( 12.34.toFixed(1) ); // 12.3

…Но если число целое, то будет проблема:

alert(12.toFixed(1)); // ошибка!

Ошибка произойдёт потому, что JavaScript ожидает десятичную дробь после точки.

Это — особенность синтаксиса JavaScript. Вот так — будет работать:

alert( 12..toFixed(1) ); // 12.0

Итого

В этой главе мы познакомились с методами и свойствами.

Почти все значения в JavaScript, кроме разве что nullи undefinedимеют их и предоставляют через них разный функционал.

Далее мы подробно разберём основные свойства и методы структур данных в JavaScript.

Числа

Все числа в JavaScript, как целые так и дробные, имеют тип Numberи хранятся в 64-битном формате

IEEE-754 , также известном как «double precision».

Здесь мы рассмотрим различные тонкости, связанные с работой с числами в JavaScript.

Способы записи

В JavaScript можно записывать числа не только в десятичной, но и в шестнадцатеричной (начинается с 0x), а также восьмеричной (начинается с 0) системах счисления:

alert( 0xFF ); // 255 в шестнадцатиричной системе alert( 010 ); // 8 в восьмеричной системе

Также доступна запись в «научном формате» (ещё говорят «запись с плавающей точкой»), который выглядит как <число>e<кол во нулей>.

Например, 1e3— это 1с 3нулями, то есть 1000.

// еще пример научной формы: 3 с 5 нулями alert( 3e5 ); // 300000

Если количество нулей отрицательно, то число сдвигается вправо за десятичную точку, так что получается десятичная дробь:

// здесь 3 сдвинуто 5 раз вправо, за десятичную точку.

alert( 3e 5 ); // 0.00003 < 5 нулей, включая начальный ноль

Деление на ноль, Infinity

Представьте, что вы собираетесь создать новый язык… Люди будут называть его «JavaScript» (или

LiveScript… неважно).

Что должно происходить при попытке деления на ноль?

Как правило, ошибка в программе… Во всяком случае, в большинстве языков программирования это именно так.

Но создатель JavaScript решил пойти математически правильным путем. Ведь чем меньше делитель, тем больше результат. При делении на очень-очень маленькое число должно получиться очень большое. В математическом анализе это описывается через пределы , и если подразумевать предел, то в качестве результата деления на 0мы получаем «бесконечность», которая обозначается

символом или, в JavaScript: "Infinity".

alert( 1 / 0 ); // Infinity alert( 12345 / 0 ); // Infinity

Infinity— особенное численное значение, которое ведет себя в точности как математическая бесконечность .

Infinityбольше любого числа.

Добавление к бесконечности не меняет её.

alert( Infinity > 1234567890 ); // true alert( Infinity + 5 == Infinity ); // true

Бесконечность можно присвоить и в явном виде: var x = Infinity.

Бывает и минус бесконечность Infinity:

alert( 1 / 0 ); // Infinity

Бесконечность можно получить также, если сделать ну очень большое число, для которого количество разрядов в двоичном представлении не помещается в соответствующую часть стандартного 64-битного формата, например:

alert( 1e500 ); // Infinity

NaN

Если математическая операция не может быть совершена, то возвращается специальное значение

NaN(Not-A-Number).

Например, деление 0/0в математическом смысле неопределено, поэтому его результат NaN:

alert( 0 / 0 ); // NaN

Значение NaNиспользуется для обозначения математической ошибки и обладает следующими свойствами:

Значение NaN— единственное, в своем роде, которое не равно ничему, включая себя.

Следующий код ничего не выведет:

if (NaN == NaN) alert( "==" ); // Ни один вызов if (NaN === NaN) alert( "===" ); // не сработает

Значение NaNможно проверить специальной функцией isNaN(n), которая преобразует аргумент к числу и возвращает true, если получилось NaN, и false— для любого другого значения.

var n = 0 / 0;

alert( isNaN(n) ); // true

alert( isNaN("12") ); // false, строка преобразовалась к обычному числу 12

Забавный способ проверки на NaN

Отсюда вытекает забавный способ проверки значения на NaN: можно проверить значение на равенство самому себе, если не равно — то NaN:

var n = 0 / 0;

if (n !== n) alert( 'n = NaN!' );

Это работает, но для наглядности лучше использовать isNaN(n).

Значение NaN«прилипчиво». Любая операция с NaNвозвращает NaN.

alert( NaN + 1 ); // NaN

Если аргумент isNaN— не число, то он автоматически преобразуется к числу.

Математические операции в JS безопасны

Никакие математические операции в JavaScript не могут привести к ошибке или «обрушить» программу.

В худшем случае, результат будет NaN.

isFinite(n)

Итак, в JavaScript есть обычные числа и три специальных числовых значения: NaN, Infinityи

Infinity.

Тот факт, что они, хоть и особые, но — числа, демонстрируется работой оператора +:

var value = prompt("Введите Infinity", 'Infinity'); var number = +value;

alert( number ); // Infinity, плюс преобразовал строку "Infinity" к такому "числу"

Обычно если мы хотим от посетителя получить число, то Infinityили NaNнам не подходят. Для того, чтобы отличить «обычные» числа от таких специальных значений, существует функция

isFinite.

Функция isFinite(n)преобразует аргумент к числу и возвращает true, если это не

NaN/Infinity/ Infinity:

alert( isFinite(1) ); // true

alert( isFinite(Infinity) ); // false alert( isFinite(NaN) ); // false

Преобразование к числу

Большинство арифметических операций и математических функций преобразуют значение в число автоматически.

Для того, чтобы сделать это явно, обычно перед значением ставят унарный плюс '+':

var s = "12.34"; alert( +s ); // 12.34

При этом, если строка не является в точности числом, то результат будет NaN:

alert( +"12test" ); // NaN

Единственное исключение — пробельные символы в начале и в конце строки, которые

игнорируются:

alert( +" 12" ); // 12

alert( +" \n34 \n" ); // 34, перевод строки \n является пробельным символом alert( +"" ); // 0, пустая строка становится нулем

alert( +"1 2" ); // NaN, пробел посередине числа ошибка

Аналогичным образом происходит преобразование и в других математических операторах и функциях:

alert( '12.34' / " 2" ); // 6.17

Мягкое преобразование: parseInt и parseFloat

В мире HTML/CSS многие значения не являются в точности числами. Например, метрики CSS: 10pt

или 12px.

Оператор '+'для таких значений возвратит NaN:

alert(+"12px") // NaN

Для удобного чтения таких значений существует функция parseInt:

alert( parseInt('12px') ); // 12

Функция parseIntи ее аналог parseFloatпреобразуют строку символ за символом, пока это возможно.

При возникновении ошибки возвращается число, которое получилось. Функция parseIntчитает из строки целое число, а parseFloat— дробное.

alert(parseInt('12px')) // 12, ошибка на символе 'p' alert(parseFloat('12.3.4')) // 12.3, ошибка на второй точке

Конечно, существуют ситуации, когда parseInt/parseFloatвозвращают NaN. Это происходит при ошибке на первом же символе:

alert( parseInt('a123') ); // NaN

Проверка на число

Для проверки строки на число можно использовать функцию isNaN(str).

Она преобразует строку в число аналогично +, а затем вернёт true, если это NaN, т.е. если

преобразование не удалось:

var x = prompt("Введите значение", " 11.5");

if (isNaN(x)) {

alert( "Строка преобразовалась в NaN. Не число" );

}else {

alert( "Число" );

}

Однако, у такой проверки есть две особенности:

1.Пустая строка и строка из пробельных символов преобразуются к 0, поэтому считаются числами.

2.Если применить такую проверку не к строке, то могут быть сюрпризы, в частности isNaN посчитает числами значения false, true, null, так как они хотя и не числа, но преобразуются к ним.

alert( isNaN(null) ); // false не NaN, т.е. "число" alert( isNaN("\n \n") ); // false не NaN, т.е. "число"

Если такое поведение допустимо, то isNaN— приемлемый вариант.

Если же нужна действительно точная проверка на число, которая не считает числом строку из пробелов, логические и специальные значения, а также отсекает Infinity— используйте

следующую функцию isNumeric:

function isNumeric(n) {

return !isNaN(parseFloat(n)) && isFinite(n);

}

Разберёмся, как она работает. Начнём справа.

Функция isFinite(n)преобразует аргумент к числу и возвращает true, если это не Infinity/ Infinity/NaN.

Таким образом, правая часть отсеет заведомо не-числа, но оставит такие значения как true/false/nullи пустую строку '', т.к. они корректно преобразуются в числа.

Для их проверки нужна левая часть. Вызов parseFloat(true/false/null/'')вернёт NaNдля этих значений.

Так устроена функция parseFloat: она преобразует аргумент к строке, т.е. true/false/null становятся "true"/"false"/"null", а затем считывает из неё число, при этом пустая строка даёт

NaN.

Врезультате отсеивается всё, кроме строк-чисел и обычных чисел.

toString(система счисления)

Как показано выше, числа можно записывать не только в 10-чной, но и в 16-ричной системе. Но

бывает и противоположная задача: получить 16-ричное представление числа. Для этого используется метод toString(основание системы), например:

var n = 255;

alert( n.toString(16) ); // ff

В частности, это используют для работы с цветовыми значениями в браузере, вида #AABBCC.

Основание может быть любым от 2до 36.

Основание 2бывает полезно для отладки побитовых операций:

var n = 4;

alert( n.toString(2) ); // 100

Основание 36(по количеству букв в английском алфавите — 26, вместе с цифрами, которых 10)

используется для того, чтобы «кодировать» число в виде буквенно-цифровой строки. В этой системе счисления сначала используются цифры, а затем буквы от aдо z:

var n = 1234567890;

alert( n.toString(36) ); // kf12oi

При помощи такого кодирования можно «укоротить» длинный цифровой идентификатор, например чтобы выдать его в качестве URL.

Округление

Одна из самых частых операций с числом — округление. В JavaScript существуют целых 3 функции для этого.

Math.floor

Округляет вниз

Math.ceil

Округляет вверх

Math.round

Округляет до ближайшего целого

alert( Math.floor(3.1) ); // 3 alert( Math.ceil(3.1) ); // 4 alert( Math.round(3.1) ); // 3

Округление битовыми операторами

Битовые операторы делают любое число 32-битным целым, обрезая десятичную часть.

В результате побитовая операция, которая не изменяет число, например, двойное битовое НЕ — округляет его:

alert( ~~12.3 ); // 12

Любая побитовая операция такого рода подойдет, например XOR (исключающее ИЛИ, "^") с нулем:

alert( 12.3 ^ 0 ); // 12

alert( 1.2 + 1.3 ^ 0 ); // 2, приоритет ^ меньше, чем +

Это удобно в первую очередь тем, что легко читается и не заставляет ставить дополнительные скобки как Math.floor(...):

var x = a * b / c ^ 0; // читается как "a * b / c и округлить"

Округление до заданной точности

Для округления до нужной цифры после запятой можно умножить и поделить на 10 с нужным количеством нулей. Например, округлим 3.456до 2го знака после запятой:

var n = 3.456;

alert( Math.round(n * 100) / 100 ); // 3.456 > 345.6 > 346 > 3.46

Таким образом можно округлять число и вверх и вниз.

num.toFixed(precision)

Существует также специальный метод num.toFixed(precision), который округляет число numдо точности precisionи возвращает результат в виде строки:

var n = 12.34;

alert( n.toFixed(1) ); // "12.3"

Округление идёт до ближайшего значения, аналогично Math.round:

var n = 12.36;

alert( n.toFixed(1) ); // "12.4"

Итоговая строка, при необходимости, дополняется нулями до нужной точности:

var n = 12.34;

alert( n.toFixed(5) ); // "12.34000", добавлены нули до 5 знаков после запятой

Если нам нужно именно число, то мы можем получить его, применив '+'к результату n.toFixed(..):

var n = 12.34;

alert( +n.toFixed(5) ); // 12.34

Метод toFixedне эквивалентен Math.round!

Например, произведём округление до одного знака после запятой с использованием двух способов: toFixedи Math.roundс умножением и делением:

var price = 6.35;

alert( price.toFixed(1) ); // 6.3

alert( Math.round(price * 10) / 10 ); // 6.4

Как видно, результат разный! Вариант округления через Math.roundполучился более корректным, так как по общепринятым правилам 5округляется вверх. А toFixedможет округлить его как вверх, так и вниз. Почему? Скоро узнаем!

Неточные вычисления

Запустите этот пример:

alert( 0.1 + 0.2 == 0.3 );

Запустили? Если нет — все же сделайте это.

Ок, вы запустили его. Он вывел false. Результат несколько странный, не так ли? Возможно, ошибка в браузере? Поменяйте браузер, запустите еще раз.

Хорошо, теперь мы можем быть уверены: 0.1 + 0.2это не 0.3. Но тогда что же это?

alert( 0.1 + 0.2 ); // 0.30000000000000004

Как видите, произошла небольшая вычислительная ошибка, результат сложения 0.1 + 0.2немного больше, чем 0.3.

alert( 0.1 + 0.2 > 0.3 ); // true

Всё дело в том, что в стандарте IEEE 754 на число выделяется ровно 8 байт(=64 бита), не больше и не меньше.

Число 0.1 (одна десятая)записывается просто в десятичном формате, а в двоичной системе

счисления это бесконечная дробь (перевод десятичной дроби в двоичную систему ). Также бесконечной дробью является 0.2 (=2/10).

Двоичное значение бесконечных дробей хранится только до определенного знака, поэтому возникает неточность. Её даже можно увидеть:

alert( 0.1.toFixed(20) ); // 0.10000000000000000555

Когда мы складываем 0.1и 0.2, то две неточности складываются, получаем незначительную, но всё же ошибку в вычислениях.

Конечно, это не означает, что точные вычисления для таких чисел невозможны. Они возможны. И даже необходимы.

Например, есть два способа сложить 0.1и 0.2:

1. Сделать их целыми, сложить, а потом поделить:

alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3

Это работает, т.к. числа 0.1*10 = 1и 0.2*10 = 2могут быть точно представлены в двоичной системе.

2.Сложить, а затем округлить до разумного знака после запятой. Округления до 10-го знака обычно бывает достаточно, чтобы отсечь ошибку вычислений:

var result = 0.1 + 0.2;

alert( +result.toFixed(10) ); // 0.3

Забавный пример

Привет! Я — число, растущее само по себе!

alert( 9999999999999999 ); // выведет 10000000000000000

Причина та же — потеря точности.

Из 64бит, отведённых на число, сами цифры числа занимают до 52бит, остальные 11бит хранят позицию десятичной точки и один бит — знак. Так что если 52бит не хватает на цифры, то при записи пропадут младшие разряды.

Интерпретатор не выдаст ошибку, но в результате получится «не совсем то число», что мы и видим в примере выше. Как говорится: «как смог, так записал».

Ради справедливости заметим, что в точности то же самое происходит в любом другом языке, где

используется формат IEEE 754, включая Java, C, PHP, Ruby, Perl.

Другие математические методы

JavaScript предоставляет базовые тригонометрические и некоторые другие функции для работы с числами.

Тригонометрия

Встроенные функции для тригонометрических вычислений:

Math.acos(x)

Возвращает арккосинус x(в радианах)

Math.asin(x)

Возвращает арксинус x(в радианах)

Math.atan(x)

Возвращает арктангенс x(в радианах)

Math.atan2(y, x)

Возвращает угол до точки (y, x). Описание функции: Atan2 .

Math.sin(x)

Вычисляет синус x(в радианах)

Math.cos(x)

Вычисляет косинус x(в радианах)

Math.tan(x)

Возвращает тангенс x(в радианах)

Функции общего назначения

Разные полезные функции:

Math.sqrt(x)

Возвращает квадратный корень из x.

Math.log(x)

Возвращает натуральный (по основанию e) логарифм x.

Math.pow(x, exp)

Возводит число в степень, возвращает exp, например . Работает в том числе с x Math.pow(2,3) = 8

дробными и отрицательными степенями, например: Math.pow(4, 1/2) = 0.5.

Math.abs(x)

Возвращает абсолютное значение числа

Math.exp(x)

Возвращает x, где — основание натуральных логарифмов. e e

Math.max(a, b, c...)

Возвращает наибольший из списка аргументов

Math.min(a, b, c...)

Возвращает наименьший из списка аргументов

Math.random()

Возвращает псевдо-случайное число в интервале [0,1) – то есть между 0(включительно) и 1(не включая). Генератор случайных чисел инициализуется текущим временем.

Форматирование

Для красивого вывода чисел в стандарте ECMA 402 есть метод toLocaleString():

var number = 123456789;

alert( number.toLocaleString() ); // 123 456 789

Его поддерживают все современные браузеры, кроме IE10- (для которых нужно подключить библиотеку Intl.JS ). Он также умеет форматировать валюту и проценты. Более подробно про устройство этого метода можно будет узнать в статье Intl: интернационализация в JavaScript, когда это вам понадобится.

Итого

Числа могут быть записаны в шестнадцатиричной, восьмеричной системе, а также «научным» способом.

В JavaScript существует числовое значение бесконечность Infinity.

Ошибка вычислений дает NaN.

Арифметические и математические функции преобразуют строку в точности в число, игнорируя начальные и конечные пробелы.

Функции parseInt/parseFloatделают числа из строк, которые начинаются с числа.

Есть четыре способа округления: Math.floor, Math.round, Math.ceilи битовый оператор. Для округления до нужного знака используйте +n.toFixed(p)или трюк с умножением и делением на

p.

10

Дробные числа дают ошибку вычислений. При необходимости ее можно отсечь округлением до нужного знака.

Случайные числа от 0до 1генерируются с помощью Math.random(), остальные — преобразованием из них.

Существуют и другие математические функции. Вы можете ознакомиться с ними в справочнике в

разделах Number и Math.

Задачи

Интерфейс суммы

важность: 5

Создайте страницу, которая предлагает ввести два числа и выводит их сумму.

Запустить демо

P.S. Есть «подводный камень» при работе с типами.

К решению

Почему 6.35.toFixed(1) == 6.3?

важность: 4

В математике принято, что 5округляется вверх, например:

alert( 1.5.toFixed(0) ); // 2 alert( 1.35.toFixed(1) ); // 1.4

Но почему в примере ниже 6.35округляется до 6.3?

alert( 6.35.toFixed(1) ); // 6.3

К решению

Сложение цен

важность: 5

Представьте себе электронный магазин. Цены даны с точностью до копейки(цента, евроцента и т.п.).

Вы пишете интерфейс для него. Основная работа происходит на сервере, но и на клиенте все должно быть хорошо. Сложение цен на купленные товары и умножение их на количество является обычной операцией.

Получится глупо, если при заказе двух товаров с ценами 0.10$и 0.20$человек получит общую

стоимость 0.30000000000000004$:

alert( 0.1 + 0.2 + '$' );

Что можно сделать, чтобы избежать проблем с ошибками округления?

К решению

Бесконечный цикл по ошибке

важность: 4

Этот цикл – бесконечный. Почему?

var i = 0;

while (i != 10) { i += 0.2;

}

К решению

Как получить дробную часть числа?

важность: 4

Напишите функцию getDecimal(num), которая возвращает десятичную часть числа:

alert( getDecimal(12.345) ); // 0.345 alert( getDecimal(1.2) ); // 0.2 alert( getDecimal( 1.2) ); // 0.2

Открыть песочницу с тестами для задачи.

К решению

Формула Бине

важность: 4

Последовательность чисел Фибоначчи имеет формулу F = F

+ F . То есть, следующее число

n n 1

n 2

получается как сумма двух предыдущих.

 

Первые два числа равны 1, затем 2(1+1), затем 3(1+2), 5(2+3)и так далее: 1, 1, 2, 3, 5, 8, 13,

21...

Код для их вычисления (из задачи Числа Фибоначчи):

function fib(n) { var a = 1,

b = 0, x;

for (i = 0; i < n; i++) { x = a + b;

a = b b = x;

}

return b;

}

Существует формула Бине

 

, согласно которой F равно ближайшему целому для ϕ/√5, где ϕ=

 

 

n

 

 

n

(1+√5)/2— золотое сечение.

Напишите функцию fibBinet(n), которая будет вычислять F, используя эту формулу. Проверьте её n

для значения F (должно получиться fibBinet(77) = 5527939700884757).

77

Одинаковы ли результаты, полученные при помощи кода fib(n)выше и по формуле Бине? Если нет, то почему и какой из них верный?

К решению

Случайное из интервала (0, max)

важность: 2

Напишите код для генерации случайного значения в диапазоне от 0до max, не включая max.

К решению

Случайное из интервала (min, max)

важность: 2

Напишите код для генерации случайного числа от minдо max, не включая max.

К решению

Случайное целое от min до max