# Arrays with numeric indexes *Array* -- is a special kind of objects, suited to store ordered, numbered collections of values. It provides additional methods to manipulate the collection. For instance, we can use arrays to keep a list of students in the group, a list of goods in the catalog etc. [cut] ## Definition There are two syntaxes for creating an empty array: ```js let arr = new Array(); let arr = []; ``` Almost all the time, the second syntax is used. We can also list elements in the brackets: ```js let fruits = ["Apple", "Orange", "Plum"]; ``` Array elements are numbered, starting with zero. We can get an element by its number in square brackets: ```js run let fruits = ["Apple", "Orange", "Plum"]; alert( fruits[0] ); // Apple alert( fruits[1] ); // Orange alert( fruits[2] ); // Plum ``` We can replace an element: ```js fruits[2] = 'Pear'; // now ["Apple", "Orange", "Pear"] ``` ...Or add to the array: ```js fruits[3] = 'Lemon'; // now ["Apple", "Orange", "Plum", "Lemon"] ``` The total count of the elements in the array is its `length`: ```js run let fruits = ["Apple", "Orange", "Plum"]; alert( fruits.length ); // 3 ``` **We can also use `alert` to show the whole array.** ```js run let fruits = ["Apple", "Orange", "Plum"]; alert( fruits ); // Apple,Orange,Plum ``` **An array can store elements of any type.** For instance: ```js run no-beautify // mix of values let arr = [ 1, 'Apple', { name: 'John' }, true, function() {} ]; // get the object at index 2 and then its name alert( arr[2].name ); // John ``` ## Методы 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). В классическом программировании так называют упорядоченную коллекцию элементов, такую что элементы добавляются в конец, а обрабатываются -- с начала. ![](queue.png) В реальной жизни эта структура данных встречается очень часто. Например, очередь сообщений, которые надо показать на экране. Очень близка к очереди еще одна структура данных: [стек](http://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B5%D0%BA). Это такая коллекция элементов, в которой новые элементы добавляются в конец и берутся с конца. ![](stack.png) Например, стеком является колода карт, в которую новые карты кладутся сверху, и берутся -- тоже сверху. Для того, чтобы реализовывать эти структуры данных, и просто для более удобной работы с началом и концом массива существуют специальные методы. ### Конец массива `pop` : Удаляет *последний* элемент из массива и возвращает его: ```js run var fruits = ["Яблоко", "Апельсин", "Груша"]; alert( fruits.pop() ); // удалили "Груша" alert( fruits ); // Яблоко, Апельсин ``` `push` : Добавляет элемент *в конец* массива: ```js run var fruits = ["Яблоко", "Апельсин"]; fruits.push("Груша"); alert( fruits ); // Яблоко, Апельсин, Груша ``` Вызов `fruits.push(...)` равнозначен `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` и выводит всё через запятую. Отсутствие значений даёт несколько запятых подряд. ```` ### Влияние на быстродействие Методы `push/pop` выполняются быстро, а `shift/unshift` -- медленно. ![](array-speed.png) Чтобы понять, почему работать с концом массива -- быстрее, чем с его началом, разберём подробнее происходящее при операции: ```js fruits.shift(); // убрать 1 элемент с начала ``` При этом, так как все элементы находятся в своих ячейках, просто удалить элемент с номером `0` недостаточно. Нужно еще и переместить остальные элементы на их новые индексы. Операция `shift` должна выполнить целых три действия: 1. Удалить нулевой элемент. 2. Переместить все свойства влево, с индекса `1` на `0`, с `2` на `1` и так далее. 3. Обновить свойство `length`. ![](array-shift.png) **Чем больше элементов в массиве, тем дольше их перемещать, это много операций с памятью.** Аналогично работает `unshift`: чтобы добавить элемент в начало массива, нужно сначала перенести вправо, в увеличенные индексы, все существующие. А что же с `push/pop`? Им как раз перемещать ничего не надо. Для того, чтобы удалить элемент, метод `pop` очищает ячейку и укорачивает `length`. Действия при операции: ```js fruits.pop(); // убрать 1 элемент с конца ``` ![](array-pop.png) **Перемещать при `pop` не требуется, так как прочие элементы после этой операции остаются на тех же индексах.** Аналогично работает `push`. ## Перебор элементов Для перебора элементов обычно используется цикл: ```js run var arr = ["Яблоко", "Апельсин", "Груша"]; *!* for (var i = 0; i < arr.length; i++) { alert( arr[i] ); } */!* ``` ````warn header="Не используйте `for..in` для массивов" Так как массив является объектом, то возможен и вариант `for..in`: ```js run var arr = ["Яблоко", "Апельсин", "Груша"]; *!* for (var key in arr) { */!* alert( arr[key] ); // Яблоко, Апельсин, Груша } ``` Недостатки этого способа: 1. Цикл `for..in` выведет *все свойства* объекта, а не только цифровые. В браузере, при работе с объектами страницы, встречаются коллекции элементов, которые по виду как массивы, но имеют дополнительные нецифровые свойства. При переборе таких "похожих на массив" коллекций через `for..in` эти свойства будут выведены, а они как раз не нужны. Бывают и библиотеки, которые предоставляют такие коллекции. Классический `for` надёжно выведет только цифровые свойства, что обычно и требуется. 2. Цикл `for (var i=0; i