Объект Math
Мы уже видели, что Math – набор инструментов для работы с числами, такими, как Math.max (максимум), Math.min (минимум), и Math.sqrt (квадратный корень).
Объект Math используется просто как контейнер для группировки связанных функций. Есть только один объект Math, и он почти не используется в виде значений. Он просто предоставляет пространство имён для всех этих функций и значений, чтоб не нужно было делать их глобальными.
Слишком большое число глобальных переменных "загрязняет" пространство имён. Чем больше имён занято, тем больше вероятность случайно использовать одно из них в качестве переменной. К примеру, весьма вероятно, что вы захотите использовать имя max для чего-то в своей программе. Поскольку встроенная в JavaScript функция max безопасно упакована в объект Math, нам не нужно волноваться по поводу того, что мы её перезапишем.
Многие языки остановят вас, или хотя бы предупредят, когда вы будете определять переменную с именем, которое уже занято. JavaScript не будет этого делать, поэтому будьте осторожны.
Возвращаясь к объекту Math, если вам нужна тригонометрия, он вам поможет. У него есть cos (косинус), sin (синус), и tan (тангенс), их обратные функции - acos, asin, и atan. Число π (pi) – или, по крайней мере, его близкая аппроксимация, помещающаяся в число JavaScript – также доступно как Math.PI. (Есть такая старая традиция в программировании - записывать имена констант в верхнем регистре.)
function randomPointOnCircle(radius) {
var angle = Math.random() * 2 * Math.PI;
return {x: radius * Math.cos(angle),
y: radius * Math.sin(angle)};
}
console.log(randomPointOnCircle(2));
// → {x: 0.3667, y: 1.966}
Если вы незнакомы с синусами и косинусами – не отчаивайтесь. Мы их будем использовать в 13 главе, и тогда я их объясню.
В предыдущем примере используется Math.random. Это функция, возвращающая при каждом вызове новое псевдослучайное число между нулём и единицей (включая ноль).
console.log(Math.random());
// → 0.36993729369714856
console.log(Math.random());
// → 0.727367032552138
console.log(Math.random());
// → 0.40180766698904335
Хотя компьютеры – машины детерминированные (они всегда реагируют одинаково на одни и те же входные данные), возможно заставить их выдавать кажущиеся случайными числа. Для этого машина хранит у себя во внутреннем состоянии несколько чисел. Каждый раз, когда идёт запрос на случайное число, она выполняет разные сложные детерминированные вычисления и возвращает часть результата вычислений. Этот результат она использует для того, чтобы изменить своё внутреннее состояние, поэтому следующее "случайное" число получается другим.
Если вам нужно целое случайное число, а не дробь, вы можете использовать Math.floor (округляет число вниз до ближайшего целого) на результате Math.random.
console.log(Math.floor(Math.random() * 10));
// → 2
Умножая случайное число на 10, получаем число от нуля до 10 (включая ноль). Так как Math.floor округляет вниз, мы получим число от 0 до 9 включительно.
Есть также функция Math.ceil (от "ceiling" – потолок, округляет вверх до ближайшего целого) и Math.round (округляет до ближайшего целого).
Объект global
К глобальной области видимости, где живут глобальные переменные, можно также получить доступ как к объекту. Каждая глобальная переменная является свойством этого объекта. В браузерах глобальная область видимости хранится в переменной window.
var myVar = 10;
console.log("myVar" in window);
// → true
console.log(window.myVar);
// → 10
Итог
Объекты и массивы (которые представляют из себя подвид объектов) позволяют сгруппировать несколько величин в одну. В принципе, это позволяет нам засунуть несколько связанных между собой вещей в мешок и бегать с ним кругами, вместо того, чтобы пытаться сгребать все эти вещи руками и пытаться держать их каждую по отдельности.
У большинства величин в JavaScript есть свойства, исключение составляют null и undefined. Мы получаем доступ к ним через value.propName или value["propName"]. Объекты используют имена для хранения свойств и хранят более-менее фиксированное их количество. Массивы обычно содержат переменное количество сходных по типу величин и используют числа (начиная с нуля) в качестве имён этих величин.
Также в массивах есть именованные свойства, такие как length, и несколько методов. Методы – это функции, живущие среди свойств и (обычно) работающие над той величиной, чьим свойством они являются.
Объекты также могут работать как карты, ассоциируя значения с именами. Оператор in используется для выяснения того, содержит ли объект свойство с данным именем. Это же ключевое слово используется в цикле for (for (var name in object)) для перебора всех свойств объекта.
Упражнения
Сумма диапазона
Во введении был упомянут удобный способ подсчёта сумм диапазонов чисел:
console.log(sum(range(1, 10)));
Напишите функцию range, принимающую два аргумента – начало и конец диапазона – и возвращающую массив, который содержит все числа из него, включая начальное и конечное.
Затем напишите функцию sum, принимающую массив чисел и возвращающую их сумму. Запустите указанную выше инструкцию и убедитесь, что она возвращает 55.
В качестве бонуса дополните функцию range, чтобы она могла принимать необязательный третий аргумент – шаг для построения массива. Если он не задан, шаг равен единице. Вызов функции range(1, 10, 2) должен будет вернуть [1, 3, 5, 7, 9]. Убедитесь, что она работает с отрицательным шагом так, что вызов range(5, 2, -1) возвращает [5, 4, 3, 2].
console.log(sum(range(1, 10)));
// → 55
console.log(range(5, 2, -1));
// → [5, 4, 3, 2]
Обращаем вспять массив
У массивов есть метод reverse, меняющий порядок элементов в массиве на обратный. В качестве упражнения напишите две функции, reverseArray и reverseArrayInPlace. Первая получает массив как аргумент и выдаёт новый массив – с обратным порядком элементов. Вторая работает как оригинальный метод reverse – она меняет порядок элементов на обратный в том массиве, который был ей передан в качестве аргумента. Не используйте стандартный метод reverse.
Если иметь в виду побочные эффекты и чистые функции из предыдущей главы, какой из вариантов вам кажется более полезным? Какой более эффективным?
console.log(reverseArray(["A", "B", "C"]));
// → ["C", "B", "A"];
var arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
// → [5, 4, 3, 2, 1]
Список
Объекты могут быть использованы для построения различных структур данных. Часто встречающаяся структура – список (не путайте с массивом). Список – связанный набор объектов, где первый объект содержит ссылку на второй, второй – на третий, и т. п.
var list = {
value: 1,
rest: {
value: 2,
rest: {
value: 3,
rest: null
}
}
};
В результате объекты формируют цепочку: