Пропустить навигацию

Лекция 8. Массивы, объект Date

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

Массив в других языках – Непрерывный участок памяти, доступ к элементам которого возможен с помощью индексов. В других языках массив – совокупность однотипных данных, одного типа и размера.

Массив – это объект, напоминающий список, который обладает некоторыми методами и свойствами. Ни размер, ни тип элементов массива не фиксированы. В одном массиве можно хранить самые разные значения, числа, строки, объекты, другие массивы. Никто не контролирует то, что мы будем хранить в массиве. Размер ячеек не фиксирован.

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

Длина массива не является верхней границей. Длина это свойство массива

Например, при создании электронного магазина нужно хранить список товаров — для таких задач и придуман массив.

Объявление

Синтаксис для создания нового массива — квадратные скобки со списком элементов внутри.

Пустой массив: var arr = [];

Массив fruits с тремя элементами:

var fruits = ["Яблоко", "Апельсин", "Слива"];

Мы задаем их в  том порядке, в котором они будут в массиве. Квадратные скобки рекомендуется использовать.

Следующий способ объявления массива – с помощью конструктора New Array. Но здесь надо быть осторожней. Можно передавать данные,  в третьей строке – New Array с одним числом – значит, что создан массив длиной три элемента. Если бы было (3,2) – то был бы массив из элементов чисел 3 и 2.

var names =  new Array(3);
names[0]  = "Petr PETROV";
names[1]  = "Ivan IVANOV";
names[2]  = "Irina SIDOROVA";

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

var students = [“Sasha", “Masha", “Dasha"];
alert(students [0]); // Sasha
alert(students [1]); // Masha
alert(students [2]); // Dasha

Элемент можно всегда заменить:

students[2] = 'Misha'; // теперь [“Sasha", “Masha", "Misha"]

 … Или добавить:

students[3] = 'Ksusha'; // теперь [“Sasha", “Masha", "Misha", "Ksusha"]

Свойство length – не длина массива, а индекс последнего элемента + 1:

var students = [“Sasha", “Masha", “Dasha"];
alert (students.length); // 3
students[10] = ‘Ksusha’;
alert (students.length); // 11
alert(students[8]);  // undefined

var arr = [];
arr[1000] = true;
alert(arr.length); // 1001

Вообще, если у вас элементы массива нумеруются случайно или с большими пропусками, то стоит подумать о том, чтобы использовать обычный объект.

Массивы предназначены именно для работы с непрерывной упорядоченной коллекцией элементов.

Значение length можно изменять . Если изменить length меньше текущего – то всё что идет за ним отрежется. Это простой способ отрезать хвосты у массивов. Причем этот процесс необратимый, т.е. даже если потом вернуть length обратно — значения не восстановятся.

var arr = [1, 2, 3, 4, 5]; 
arr.length = 2; // укоротить до 2 элементов
alert(arr); // [1, 2]
arr.length = 5; // вернуть length обратно, как было
alert(arr[3]); // undefined: значения не вернулись

Самый простой способ очистить массив — это arr.length=0.

Через alert можно вывести и массив целиком. При этом его элементы будут перечислены через запятую:

var students = [“Sasha", “Masha", “Dasha"];
alert(students);// Sasha, Masha, Dasha


В массиве может храниться любое число элементов любого типа. В том числе, строки, числа, объекты и т.п.:

В яваскрипт нет двумерных массивов. Но можно положить в массив другой массив.

Var arr = [1, “stroke”, { a : 345 }, [ 2, 3, 5]]
Var j = [[1,2,3],[4,5,6],[7,8,9]]
Alert( J[0][1]);  // 2



Методы объекта Array.

Методы объекта Array:

concat – объединение массивов в один

Метод arr.concat(value1, value2, … valueN) создаёт новый массив, в который копируются элементы из arr, а также value1, value2, ... valueN.

Например:

var arr = [1,2];
var newArr = arr.concat(3,4);
alert(newArr); // 1,2,3,4


Если value — массив, то concat добавляет его элементы.

Например:

var arr = [1,2];
var newArr = arr.concat( [3,4], 5); // то же самое, что arr.concat(3,4,5)
alert(newArr); // 1,2,3,4,5

join – объединение всех элементов массива в строку

Вызов arr.join(str) делает в точности противоположное split. Он берет массив и склеивает его в строку, используя str как разделитель.

Например: 

var arr = ['Маша', 'Петя', 'Марина', 'Василий'];
var str = arr.join(';');
alert(str); // Маша;Петя;Марина;Василий


Методы pop/push, shift/unshift

Одно из применений массива — это очередь. В классическом программировании так называют упорядоченную коллекцию элементов, такую, что элементы добавляются в конец, а обрабатываются — с начала.

В реальной жизни эта структура данных встречается очень часто. Например, очередь сообщений, которые надо отослать.

Очень близка к очереди еще одна структура данных: стек. Это такая коллекция элементов, в которой новые элементы добавляются в конец и берутся с конца.

Например, стеком является колода карт, в которую новые карты кладутся сверху, и берутся — тоже сверху. Для того, чтобы реализовывать эти структуры данных, и просто для более удобной работы с началом и концом массива существуют специальные методы.

Конец массива

pop – удаление последнего элемента в массиве

Удаляет последний элемент из массива и возвращает его:

var fruits = ["Мандарин", "Апельсин", "Лимон"];
alert( fruits.pop() ); // удалили "Лимон"
alert(fruits); // Яблоко, Апельсин


push
– добавлении элементов в конец массива

Добавляет элемент в конец массива:

var fruits = ["Яблоко", "Апельсин"];
fruits.push("Груша");
alert(fruits); // Яблоко, Апельсин, Груша

Начало массива

Является полным аналогом fruits[fruits.length] = ....

shift – удаление первого элемента массива

Удаляет из массива первый элемент и возвращает его:

var fruits = ["Яблоко", "Апельсин", "Груша"];
alert( fruits.shift() ); // удалили Яблоко
alert(fruits); // Апельсин, Груша

 unshift – добавление элементов в начало массива

Добавляет элемент в начало массива:

var fruits = ["Апельсин", "Груша"];
fruits.unshift('Яблоко');
alert(fruits); // Яблоко, Апельсин, Груша

Методы push и unshift могут добавлять сразу по несколько элементов: 

var fruits = ["Яблоко"];
fruits.push("Апельсин", "Персик");
fruits.unshift("Ананас", "Лимон");
// результат: ["Ананас", "Лимон", "Яблоко", "Апельсин", "Персик"]
alert(fruits);


Влияние на быстродействие

Методы push/pop выполняются быстро, а shift/unshift — медленно.

Чтобы понять, почему работать с концом массива — быстрее, чем с его началом, разберём происходящее подробнее.

Операция shift выполняет два действия:

  1. Удалить элемент в начале.
  2. Обновить внутреннее свойство length.

При этом, так как все элементы находятся в своих ячейках, просто очистить ячейку с номером 0 недостаточно. Нужно еще и переместить все ячейки на 1 вниз (красным на рисунке подсвечены изменения): 

fruits.shift(); // убрать 1 элемент с начала


Чем больше элементов в массиве, тем дольше их перемещать.

Аналогично работает unshift: чтобы добавить элемент в начало массива, нужно сначала перенести все существующие.

У методов push/pop таких проблем нет. Для того, чтобы удалить элемент, метод pop очищает ячейку и укорачивает length. 

fruits.pop();  // убрать 1 элемент с конца


Аналогично работает push.

Встроенные методы для работы с массивом автоматически обновляют его длину length.

reverse – изменение порядка следования элементов на противоположный

Метод arr.reverse() меняет порядок элементов в массиве на обратный.

var arr = [1,2,3];
arr.reverse();
alert(arr); // 3,2,1


slice
– выделение фрагмента массива в новый массив

Метод slice(begin, end) копирует участок массива от begin до end, не включая end. Исходный массив при этом не меняется.

Например: 

var arr = ["Почему", "надо", "учить", "JavaScript"];
var arr2 = arr.slice(1,3); // элементы 1, 2 (не включая 3)
alert(arr2); // надо, учить


Аргументы ведут себя так же, как и в строковом slice:

  • Если не указать end — копирование будет до конца массива:
var arr = ["Почему", "надо", "учить", "JavaScript"];
var arr2 = arr.slice(1,3); // элементы 1, 2 (не включая 3)
alert(arr2); // надо, учить
  • Можно использовать отрицательные индексы, они отсчитываются с конца:
var arr2 = arr.slice(-2); // копировать от 2го элемента с конца и дальше
  • Если вообще не указать аргументов — скопируется весь массив:
var fullCopy = arr.slice();

 

splice – удаление и добавление элементов массива

Метод splice - это универсальный метод для работы с массивами. Умеет все: удалять элементы, вставлять элементы, заменять элементы - по очереди и одновременно.

Его синтаксис:

arr.splice(index[, deleteCount, elem1, ..., elemN])

Удалить deleteCount элементов, начиная с номера index, а затем вставить elem1, ..., elemN на их место.

Посмотрим примеры.

var arr = ["Я", "изучаю", "JavaScript"];
arr.splice(1, 1);  // начиная с позиции 1, удалить 1 элемент
alert(arr); //  осталось ["Я", "JavaScript"]

Здесь продемонстрировано, как использовать splice для удаления одного элемента**. Следующие за удаленным элементы сдвигаются, чтобы заполнить его место. 

var arr = ["Я", "изучаю", "JavaScript"];
arr.splice(0, 1);  // удалить 1 элемент, начиная с позиции 0
alert( arr[0] ); // "изучаю" стал первым элементом

Следующий пример показывает, как заменять элементы:

var arr = ["Я", "сейчас", "изучаю", "JavaScript"];

Удалить 3 первых элемента и добавить другие вместо них

arr.splice(0, 3, "Мы", "изучаем") 
alert( arr ) // теперь ["Мы", "изучаем", "JavaScript"]


 Метод splice возвращает массив из удаленных элементов:

var arr = ["Я", "сейчас", "изучаю", "JavaScript"];

Удалить 2 первых элемента 

var removed = arr.splice(0, 2); 
alert( removed ); // "Я", "сейчас" <-- array of removed elements

Метод splice также может вставлять элементы без удаления, для этого достаточно установить deleteCount в 0: 

var arr = ["Я", "изучаю", "JavaScript"];

С позиции 2

удалить 0

вставить "сложный", "язык"

arr.splice(2, 0, "сложный", "язык"); 
alert(arr); // "Я", "изучаю", "сложный", "язык", "JavaScript"

Допускается использование отрицательного номера позиции, которая в этом случае отсчитывается с конца:

var arr = [1, 2, 5]

начиная с позиции индексом -1 (предпоследний элемент)

удалить 0 элементов

затем вставить числа 3 и 4

arr.splice(-1, 0, 3, 4);
alert(arr); // результат: 1,2,3,4,5

sort – сортировка элементов массива 

Метод sort() сортирует массив на месте. Например:

var arr = [ 1, 2, 15 ];
arr.sort();
alert( arr );  // 1, 15, 2

Результат сортировки неочевиден – порядок стал 1, 15, 2. Это произошло потому, что sort сортирует, преобразуя элементы к строке. Поэтому и порядок у них строковый, ведь "2" > "15".

Свой порядок сортировки

Внутренняя реализация метода arr.sort(fn) умеет сортировать любые массивы, если указать функцию fn от двух элементов, которая умеет сравнивать их.

Если эту функцию не указать, то элементы сортируются как строки.

Например, укажем эту функцию явно, отсортируем элементы массива как числа: 

function compareNumeric(a, b) {
  if (a > b) return 1;
  if (a < b) return -1;
}
var arr = [ 1, 2, 15 ];
arr.sort(compareNumeric);
alert(arr);  // 1, 2, 15


Обратите внимание, мы передаём в sort() именно саму функцию compareNumeric, без вызова через скобки. Был бы ошибкой следующий код: 

arr.sort( compareNumeric() );  // не сработает

Алгоритм сортировки, встроенный в JavaScript, будет передавать ей для сравнения элементы массива. Она должна возвращать:К функции, передаваемой sort, есть всего одно требование.

  • Положительное значение, если a > b, 
  • Отрицательное значение, если a < b,
  • Если равны — не важно, что возвращать, их взаимный порядок не имеет значения.

Для работы с датой и временем в JavaScript используются объекты Date.

Создание

Для создания нового объекта типа Date используется один из синтаксисов:

new Date()

Создает объект Date с текущей датой и временем:

var now = new Date();
alert(now);
new Date(milliseconds)

Создает объект Date, значение которого равно количеству миллисекунд (1/1000 секунды), прошедших с 1 января 1970 года GMT+0.

24 часа после 01.01.1970 GMT+0

var Jan02_1970 = new Date(3600*24*1000);
alert( Jan02_1970 );
new Date(datestring)

Если единственный аргумент - строка, используется вызов Date.parse для ее разбора.

new Date(year, month, date, hours, minutes, seconds, ms)

Дату можно создать, используя компоненты в местной временной зоне. Для этого формата обязательны только первые два аргумента. Отсутствующие параметры, начиная с hours считаются равными нулю, а date — единице.  

Заметим, что год year должен быть из 4 цифр, а отсчет месяцев month начинается с нуля 0. Например: 

new Date(2011, 0, 1) // 1 января 2011, 00:00:00 в местной временной зоне
new Date(2011, 0) // то же самое, date по умолчанию равно 1
new Date(2011, 0, 1, 0, 0, 0, 0); // то же самое

Дата задана с точностью до миллисекунд:

var d = new Date(2011, 0, 1, 2, 3, 4, 567); 
alert(d); // 1.01.2011, 02:03:04.567

Получение компонентов даты

Для доступа к компонентам даты-времени объекта date используются следующие методы:

getFullYear()

Получить год(из 4 цифр).

getMonth()

Получить месяц, от 0 до 11.

getDate()

Получить число месяца, от 1 до 31.

getHours(), getMinutes(), getSeconds(), getMilliseconds()

Получить соответствующие компоненты.

Дополнительно можно получить день недели:

getDay()

Получить номер дня в неделе. Неделя в JavaScript начинается с воскресенья, так что результат будет числом от 0(воскресенье) до 6(суббота).

Все методы, указанные выше, возвращают результат для местной временной зоны.

Существуют также UTC-варианты этих методов, возвращающие день, месяц, год и т.п. для зоны GMT+0 (UTC): getUTCFullYear(), getUTCMonth(), getUTCDay(). То есть, сразу после "get" вставляется "UTC".

Если ваше локальное время сдвинуто относительно UTC, то следующий код покажет разные часы: 

var date = new Date();
alert( date.getHours() ); // час в вашей зоне для даты date
alert( date.getUTCHours() ); // час в зоне GMT+0 для даты date

Кроме описанных выше, существуют два специальных метода без UTC-варианта:

getTime()

Возвращает число миллисекунд, прошедших с 01.01.1970 00:00:00 UTC. Это то же число, которое используется в конструкторе new Date(milliseconds).

getTimezoneOffset()

Возвращает разницу между местным и UTC-временем, в минутах.

alert( new Date().getTimezoneOffset() );  // Для GMT-1 выведет 60

Установка компонентов даты

Следующие методы позволяют устанавливать компоненты даты и времени:

  • setFullYear(year [, month, date])
  • setMonth(month [, date])
  • setDate(date)
  • setHours(hour [, min, sec, ms])
  • setMinutes(min [, sec, ms])
  • setSeconds(sec [, ms])
  • setMilliseconds(ms)
  • setTime(millisecond) (устанавливает всю дату по миллисекундам с 01.01.1970 UTC)

Все они, кроме setTime(), обладают также UTC-вариантом, например: setUTCHours().

Как видно, некоторые методы могут устанавливать несколько компонентов даты одновременно, в частности,setHours. При этом если какая-то компонента не указана, она не меняется. Например:

var today = new Date;
today.setHours(0);
alert( today ); // сегодня, но час изменён на 0
today.setHours(0, 0, 0, 0); 
alert (today ); // сегодня, ровно 00:00:00. 

Автоисправление даты

Автоисправление — очень удобное свойство объектов Date. Оно заключается в том, что можно устанавливать заведомо некорректные компоненты (например 32 января), а объект сам себя поправит.

var d = new Date(2013, 0, 32); // 32 января 2013 ?!?
alert(d); // ... это 1 февраля 2013!

Неправильные компоненты даты автоматически распределяются по остальным.

Например, нужно увеличить на 2 дня дату «28 февраля 2011». Может быть так, что это будет 2 марта, а может быть и 1 марта, если год високосный. Но нам обо всем этом думать не нужно. Просто прибавляем два дня. Остальное сделает Date: 

var d = new Date(2011, 1, 28);
d.setDate( d.getDate() + 2 );

Также это используют для получения даты, отдаленной от имеющейся на нужный промежуток времени. Например, получим дату на 70 секунд большую текущей: 

var d = new Date();
d.setSeconds( d.getSeconds()+70);
alert(d); // выведет корректную дату

Можно установить и нулевые, и даже отрицательные компоненты. Например: 

d.setDate(1); // поставить первое число месяца
alert(d);
var d = new Date;
d.setDate(0); // нулевого числа нет, будет последнее число предыдущего месяца
alert(d);
var d = new Date;
d.setDate(-1); // предпоследнее число предыдущего месяца
alert(d);


 
Преобразование к числу, разность дат

Когда объект Date используется в числовом контексте, он преобразуется в количество миллисекунд:

alert( +new Date ) // +date то же самое, что: +date.valueOf()

Важный побочный эффект: даты можно вычитать, результат вычитания объектов Date — их временная разница, в миллисекундах.

Это используют для измерения времени:

var start = new Date; // засекли время
// что-то сделать
for (var i=0; i<100000; i++) {
  var doSomething = i*i*i; 
}
var end = new Date; // конец измерения
alert("Цикл занял " + (end-start) + " ms");


 
Встроенные в Date методы форматирования используются редко, и преимущественно, для отладки.

toString(), toDateString(), toTimeString()

Возвращают стандартное строчное представление, не указанное в стандарте, а зависящее от браузера. Единственное требование - читаемость человеком. Метод toString возвращает дату целиком, toDateString() и toTimeString() - только дату и время соответственно. 

var d = new Date();
alert( d.toString() ); // вывод, похожий на 'Wed Jan 26 2011 16:40:50 GMT+0300'


 
toLocaleString(), toLocaleDateString(), toLocaleTimeString()

То же самое, но строка должна быть с учетом локальных настроек и языка посетителя. 

var d = new Date();
alert( d.toLocaleString() ); // дата на языке посетителя


toISOString()
toUTCString()

То же самое, что toString(), но дата в зоне UTC.

Возвращает дату в формате ISO Детали формата будут далее. Поддерживается современными браузерами, не поддерживается IE<9. 

var d = new Date();
alert( d.toISOString() ); // вывод, похожий на '2011-01-26T13:51:50.417Z'

Встроенные методы форматирования Date не допускают указание собственного формата.
Все современные браузеры, включая IE9+, понимают даты в упрощённом формате ISO 8601 Extended.

Поэтому, как правило, любой вывод, кроме отладочного, форматируется своей, а не встроенной функцией.

Разбор строки, Date.parse

Этот формат выглядит так: YYYY-MM-DDTHH:mm:ss.sssZ. Для разделения даты и времени в нем используется символ 'T'. Часть 'Z' обозначает (необязательную) временную зону — она может отсутствовать, тогда зона UTC, либо может быть символ z — тоже UTC, или зона в формате +-hh:mm.

Также возможны упрощенные варианты, к примеру:

YYYY

YYYY-MM

YYYY-MM-DD

Mетод Date.parse(str) разбирает строку str в таком формате и возвращает соответствующее ей количество миллисекунд. Если это невозможно, Date.parse возвращает Nan.

var msNoZone = Date.parse('2012-01-26T13:51:50.417'); // без зоны, значит UTC
alert(msNoZone); // 1327571510417 (число миллисекунд)
var msZ = Date.parse('2012-01-26T13:51:50.417z'); // зона z означает UTC
alert(msZ == msNoZone); // true, если браузер правильный

С таймзоной -07:00 GMT в конце все современные браузеры работают правильно:

var ms = Date.parse('2012-01-26T13:51:50.417-07:00');
alert(ms); // 1327611110417 (число миллисекунд)