# Массивы c числовыми индексами *Массив с числовыми индексами* -- это коллекция данных, которая хранит сколько угодно значений, причем у каждого значения -- свой уникальный номер. Если переменная -- это *коробка для данных*, то массив -- это *шкаф с нумерованными ячейками*, в каждой из которых могут быть свои данные. [cut] Например, при создании электронного магазина нужно хранить список товаров -- для таких задач и придуман массив. ## Объявление Синтаксис для создания нового массива -- квадратные скобки со списком элементов внутри. Пустой массив: ```js var arr = []; ``` Массив `fruits` с тремя элементами: ```js var fruits = ["Яблоко", "Апельсин", "Слива"]; ``` **Элементы нумеруются, начиная с нуля.** Чтобы получить нужный элемент из массива -- указывается его номер в квадратных скобках: ```js //+ run var fruits = ["Яблоко", "Апельсин", "Слива"]; alert(fruits[0]); // Яблоко alert(fruits[1]); // Апельсин alert(fruits[2]); // Слива ``` Элемент можно всегда заменить: ```js fruits[2] = 'Груша'; // теперь ["Яблоко", "Апельсин", "Груша"] ``` ... Или добавить: ```js fruits[3] = 'Лимон'; // теперь ["Яблоко", "Апельсин", "Груша", "Лимон"] ``` Общее число элементов, хранимых в массиве, содержится в его свойстве `length`: ```js //+ run var fruits = ["Яблоко", "Апельсин", "Груша"]; alert(fruits.length); // 3 ``` **Через `alert` можно вывести и массив целиком.** При этом его элементы будут перечислены через запятую: ```js //+ run var fruits = ["Яблоко", "Апельсин", "Груша"]; alert(fruits); // Яблоко,Апельсин,Груша ``` **В массиве может храниться любое число элементов любого типа.** В том числе, строки, числа, объекты и т.п.: ```js //+ run // микс значений var arr = [ 1, 'Имя', { name: 'Петя' }, true ]; // получить объект из массива и тут же -- его свойство alert( arr[2].name ); // Петя ``` ## Методы pop/push, shift/unshift Одно из применений массива -- это [очередь](http://ru.wikipedia.org/wiki/%D0%9E%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C_%28%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%29). В классическом программировании так называют упорядоченную коллекцию элементов, такую что элементы добавляются в конец, а обрабатываются -- с начала. В реальной жизни эта структура данных встречается очень часто. Например, очередь сообщений, которые надо отослать. Очень близка к очереди еще одна структура данных: [стек](http://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B5%D0%BA). Это такая коллекция элементов, в которой новые элементы добавляются в конец и берутся с конца. Например, стеком является колода карт, в которую новые карты кладутся сверху, и берутся -- тоже сверху. Для того, чтобы реализовывать эти структуры данных, и просто для более удобной работы с началом и концом массива существуют специальные методы. ### Конец массива
`pop`
Удаляет *последний* элемент из массива и возвращает его: ```js //+ run var fruits = ["Яблоко", "Апельсин", "Груша"]; alert( fruits.pop() ); // удалили "Груша" alert(fruits); // Яблоко, Апельсин ```
`push`
Добавляет элемент *в конец* массива: ```js //+ run var fruits = ["Яблоко", "Апельсин"]; fruits.push("Груша"); alert(fruits); // Яблоко, Апельсин, Груша ``` Является полным аналогом `fruits[fruits.length] = ...`.
### Начало массива
`shift`
Удаляет из массива *первый* элемент и возвращает его: ```js var fruits = ["Яблоко", "Апельсин", "Груша"]; alert( fruits.shift() ); // удалили Яблоко alert(fruits); // Апельсин, Груша ```
`unshift`
Добавляет элемент *в начало* массива: ```js var fruits = ["Апельсин", "Груша"]; fruits.unshift('Яблоко'); alert(fruits); // Яблоко, Апельсин, Груша ```
Методы `push` и `unshift` могут добавлять сразу по несколько элементов: ```js //+ run var fruits = ["Яблоко"]; fruits.push("Апельсин", "Персик"); fruits.unshift("Ананас", "Лимон"); // результат: ["Ананас", "Лимон", "Яблоко", "Апельсин", "Персик"] alert(fruits); ``` ## Внутреннее устройство массива Массив -- это объект, где в качестве ключей выбраны цифры, с дополнительными методами и свойством `length`. Так как это объект, то в функцию он передаётся по ссылке: ```js //+ run function eat(arr) { arr.pop(); } var arr = ["нам", "не", "страшен", "серый", "волк"] alert(arr.length); // 5 eat(arr); eat(arr); alert(arr.length); // 3, в функцию массив не скопирован, а передана ссылка ``` **Ещё одно следствие -- можно присваивать в массив любые свойства.** Например: ```js var fruits = []; // создать массив fruits[99999] = 5; // присвоить свойство с любым номером fruits.age = 25; // назначить свойство со строковым именем ``` .. Но массивы для того и придуманы в JavaScript, чтобы удобно работать именно *с упорядоченными, нумерованными данными*. Для этого в них существуют специальные методы и свойство `length`. Как правило, нет причин использовать массив как обычный объект, хотя технически это и возможно. [warn header="Вывод массива с \"дырами\""] Если в массиве есть пропущенные индексы, то при выводе в большинстве браузеров появляются "лишние" запятые, например: ```js //+ run var a = []; a[0] = 0; a[5] = 5; alert(a); // 0,,,,,5 ``` Эти запятые появляются потому, что алгоритм вывода массива идёт от `0` до `arr.length` и выводит всё через запятую. Отсутствие значений даёт несколько запятых подряд. [/warn] ### Влияние на быстродействие Методы `push/pop` выполняются быстро, а `shift/unshift` -- медленно. Чтобы понять, почему работать с концом массива -- быстрее, чем с его началом, разберём происходящее подробнее. Операция `shift` выполняет два действия:
  1. Удалить элемент в начале.
  2. Обновить внутреннее свойство `length`.
При этом, так как все элементы находятся в своих ячейках, просто очистить ячейку с номером `0` недостаточно. Нужно еще и переместить все ячейки на `1` вниз (красным на рисунке подсвечены изменения): ```js *!*fruits.shift();*/!* // убрать 1 элемент с начала ``` Чем больше элементов в массиве, тем дольше их перемещать. Аналогично работает `unshift`: чтобы добавить элемент в начало массива, нужно сначала перенести все существующие. У методов `push/pop` таких проблем нет. Для того, чтобы удалить элемент, метод `pop` очищает ячейку и укорачивает `length`. ```js *!*fruits.pop();*/!* // убрать 1 элемент с конца ``` Аналогично работает `push`. ## Перебор элементов Для перебора элементов обычно используется цикл: ```js //+ run var arr = ["Яблоко", "Апельсин", "Груша"]; *!* for (var i=0; i
  • Цикл `for..in` выведет *все свойства* объекта, а не только цифровые. В браузере, при работе с объектами страницы, встречаются коллекции элементов, которые по виду как массивы, но имеют дополнительные нецифровые свойства, которые будут видны в цикле `for..in`. Бывают и библиотеки, которые предоставляют такие коллекции. Например jQuery. С виду -- массив, но есть дополнительные свойства. Для перебора только цифровых свойств нужен цикл `for(var i=0; i
  • Цикл `for (var i=0; i **Если кратко: цикл `for(var i=0; i
  • Не ставить массиву произвольные свойства, такие как `arr.test = 5`. То есть, работать именно как с массивом, а не как с объектом.
  • Заполнять массив непрерывно. Как только браузер встречает необычное поведение массива, например устанавливается значение `arr[0]`, а потом сразу `arr[1000]`, то он начинает работать с ним, как с обычным объектом. Как правило, это влечёт преобразование его в хэш-таблицу.
  • Если следовать этим принципам, то массивы будут занимать меньше памяти и быстрее работать. ## Итого Массивы существуют для работы с упорядоченным набором элементов. **Объявление:** ```js // предпочтительное var arr = [ элемент1, элемент2... ]; // new Array var arr = new Array( элемент1, элемент2...); ``` При этом `new Array(число)` создаёт массив заданной длины, *без элементов*. Чтобы избежать ошибок, предпочтителен первый синтаксис. **Свойство `length`** -- длина массива. Если точнее, то последний индекс массива плюс `1`. Если её уменьшить вручную, то массив укоротится. Если `length` больше реального количества элементов, то отсутствующие элементы равны `undefined`. Массив можно использовать как очередь или стек. **Операции с концом массива:** **Операции с началом массива:** Эти операции перенумеровывают все элементы, поэтому работают медленно. В следующей главе мы рассмотрим другие методы для работы с массивами.