Meshbeyn / JavaScript

Конспект по JavaScript

5 Массивы

Массив в JavaScript обладает гораздо большей универсальностью, чем его собратья в полноценных языках. Фактически, одним объектом реализуется функциональность массивов обычных, ассоциативных и разреженных, а также стеков и очередей обычных и двунаправленных. Функциональность ассоциативных массивов на самом деле унаследована от объектов и не является полной: массив, как и объект, позволяет правильно лишь добавлять, читать и удалять элементы. Даже перечисление элементов связано с трудностями.

В статье про объекты мы видели, что доступ к полям объектов может быть осуществлен и через оператор разиндексации. Причем, этот способ позволяет использовать как нормальные имена для полей, так и произвольные строки или числа. Внешне массив отличается от объекта только дополнительным свойством length и несколькими методами. Если злоупотребить таким сходством, то объект можно использовать как массив, а массив как объект. Новички, для которых JavaScript является первым языком программирования, часто имеют сложности с пониманием семантического различия между объектами и массивами. Грубо говоря, знающему только JavaScript не понятно, когда нужно использовать объект, а когда - массив. Полноценные языки такой путаницы не допускают.

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

Книга - это объект. Кроме листов, она имеет еще и свои дополнительные свойства: автор, название, издательство и так далее. Одним из свойств является коллекция листов. Эта коллекция - уже часть книги, без нее книга не может существовать.

Это и есть отличие объекта от коллекции: элементы коллекции только хранятся в ней, больше они никак не связаны, а вот поля объекта являются его частью и имеют смысл только вместе с ним.

Создание массива

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

var arr = [10, 20, 30];

Также можно создать массив через конструктор объекта Array, который и является родоначальником всех массивов:

var arr = new Array(10, 20, 30);

При такой записи массив автоматически имеет размер 3 и содержит 3 элемента: arr[0]=10, arr[1]=20, arr[3]=30. Если в конструкторе указать только одно число, оно будет считаться длиной массива.

Добавление, удаление, чтение и перезапись элементов

Также как и с полями объекта, доступ к элементам массива осуществляется одним выражением разиндексации. В зависимости от контекста это будет доступ для чтения или для записи.

Если выражение стоит перед оператором присваивания - это доступ для записи. Существующий элемент при таком доступе перезаписывается, а несуществующий создается.

Если выражение стоит в другом месте - это доступ для чтения. Если такой индекс не существует, возвращается значение undefined.

Для удаления элемента массива используется оператор delete.

var a = [2, 3];
a[5] = a[0] + a[1];
// 2,3,,,,5
document.write(a);

delete a[0];
// ,3,,,,5
document.write("<br />", a);
// a[0] = undefined
document.write("<br />a[0] = ", a[0]);
// a.length = 6
document.write("<br />a.length = ", a.length);

Элементы объекта Array

Как уже было сказано, каждый массив является производным от объекта Array. Это значит, что прототипом массива автоматически ставится объект Array и все методы объекта Array доступны в массиве.

Constructor, length, isArray, indexOf, lastIndexOf и join

Конструкторная функция Array без аргументов создает пустой массив нулевой длины, с одним целочисленным аргументом - массив указанной длины со значениями undefined в каждой ячейке, с другими аргументами - каждый аргумент записывается в массив начиная с нулевого индекса.

Свойство для чтения length возвращает длину массива. Все определенные ячейки имеют индексы от 0 до length-1. Если добавить новую ячейку с большим индексом, значение этого свойства автоматически изменится.

Функция Array.isArray(arr) проверяет, является ли arr действительно массивом. Возвращает булевое значение. оператор typeof возвращает для массивов тип object, поэтому на него нельзя полагаться. Эта функция используется как статическая, так как переменная arr может быть неопределена, а для остальных переменных такой вызов не имеет смысла.

Функция Array.indexOf ищет указанный объект среди элементов массива. Возвращает индекс найденного элемента или -1, если элемент не найден. Можно начинать искать с определенного индекса.

Функция Array.lastIndexOf ведет себя аналогично функции indexOf, но ищет начиная с последнего элемента и в сторону начала массива.

Функция Array.join создает строку из строковых представлений всех элементов массива, разделенных друг от друга указанной строкой - разделителем. Значения null и undefined заменяются пустой строкой.

Функции преобразования массива: sort, reverse, concat, slice, splice

Функция Array.sort сортирует элементы массива. Можно передать как параметр сравнивающую функцию.

Функция Array.reverse переставляет элементы массива в обратном порядке.

Функция Array.concat добавляет в конец массива новые элементы. Если передать в аргументах массивы, то копируются не сами массивы, а их элементы. Остальные значения копируются как есть.

Функция Array.slice возвращает интервал из массива. Аргументами функции являются начало и длина интервала. Можно указывать отрицательные значения - в таком случае они отсчитываются от конца массива.

Функия Array.splice замещает интервал в массиве другими значениями. Количество новых значений может не совпадать с длиной интервала. Соответственно, функция может за один вызов выполнять разные действия: замещать элементы массива, удалять или вставлять элементы массива.

Функции для реализации стека: push и pop

Функция Array.push добавляет новые элементы в конец массива.

Функция Array.pop удаляет из массива и возвращает его последний элемент.

Функции для реализации очереди: unshift и shift

Обе эти функции сдвигают все элементы массива, поэтому пользоваться ими нужно с осторожностью. На работу с большими массивами будет уходить слишком много времени. Для реализации односторонней очереди используйте unshift для добавления нового элемента и pop для чтения, либо наоборот push для добавления и shift для чтения. Все четыре функции push, pop, shift и unshift позволяют реализовать двустороннюю очередь.

Функция Array.unshift добавляет новые элементы в начало массива.

Функция Array.shift удаляет из массива и возвращает его первый элемент.

Предикатные функции: every, some, forEach, filter, map, reduce, reduceRight

Предикатные функции напоминают технологию LINQ из .Net: они принимают в качестве параметра функцию (предикат) и вызывают ее для каждого элемента массива. Результаты вызовов переданной функции затем обрабатываются в предикатной функции соответствующим образом. Название "предикатная" для таких функций некорректно, да и предикатом может называться лишь булевая функция, но такое название часто используется. Массив может изменяться в процессе прохода, данные функции это не запрещают и никак не обработывают. Каждая из этих функций просто проходит в цикле от первого к последнему элементу или наоборот.

Функция Array.every вызывает булевый предикат для каждого элемента и возвращает true, если все вызовы вернули true. Используется для проверки всех элементов на соответствие одному условию.

Функция Array.some вызывает булевый предикат для каждого элемента и возвращает true, если хоть один вызов вернул true. Используется для проверки наличия подходящего элемента.

Функция Array.forEach вызывает переданную функцию для каждого элемента в массиве. Используется как сокращенная запись цикла for in.

Функция Array.filter вызывает булевый предикат для каждого элемента и возвращает массив из элементов, для которых этот вызов вернул true. Используется для фильтрации из массива всех элементов, удовлетворяющих некоторому условию.

Функция Array.map вызывает переданную функцию для каждого элемента и возвращает массив из результатов этих вызовов. Используется для преобразования объектов в массиве в другие.

Функция Array.reduce вызывает переданную функцию для каждого элемента и передает ей как дополнительный аргумент результат предыдущего вызова. Используется для создания аккумуляторов. Например, соответствующая функция может суммировать элементы массива.

Функция Array.reduceRight ведет себя аналогично функции Array.reduce, но проходит массив от конца к началу.