В жизни мы часто
сталкиваемся со списками: список студентов, марок машин, значений функции,
элементов HTML-документа и
т.п. Так вот, для хранения упорядоченных коллекций существует особая структура
данных, которая называется массивом (по англ. array).
Обычно массивы в
JavaScript задаются с
помощью литерала – квадратных скобок:
let ar = []; //пустой массив
let ar = [1, 30, 0, -2]; //одномерный массив чисел
Каждый элемент
разделяется запятой. В результате мы здесь объявили массив из 4-х чисел. Или,
так:
let ar = ["Яблоко", "Апельсин", "Слива"];
Здесь имеем
массив из трех строковых элементов. Для обращения к отдельному элементу массива
используется такой синтаксис:
<имя массива>[индекс элемента]
Например,
выведем значение первого элемента массива ar в консоль:
Обратите
внимание, индекс первого элемента массива равен 0, не 1, как мы привыкли в
повседневной жизни, а 0! Запомним это. Соответственно, второй элемент имеет
индекс 1 и так далее:
console.log( ar[1] );
console.log( ar[2] );
Любой элемент
массива можно изменить, используя тот же синтаксис:
Теперь наш
массив содержит элементы: "Яблоко", "Груша",
"Слива". Вот так можно обращаться к элементам массива для считывания
или изменения их значений.
В любой массив
можно добавлять новые элементы, например, так:
Здесь мы
указываем индекс элемента, в который хотим записать значение «Лимон» и, так как
такого элемента нет, то он добавляется. В результате получаем массив из четырех
строк:
"Яблоко", "Груша", "Слива", "Лимон"
У массива есть
свойство length, хранящее
значение равное максимальному индексу плюс один:
Array.length = maxIndex+1
Используя это
свойство, можно через цикл вывести значения всех элементов массива:
for(let i=0;i < ar.length;++i)
console.log( ar[i] );
Но можно это
сделать и так:
Обратите
внимание, length – это не число
элементов массива в привычном нам виде. Например, если в наш массив добавить
еще один элемент с большим индексом:
то length = 1000, но в
массиве будет всего пять элементов:
"Яблоко",
"Груша", "Слива", "Лимон" и "Виноград"
(с индексом 999)
Далее, при
переборе такого массива через цикл, несуществующие элементы будут принимать
значения undefined и ошибки
никакой не возникнет.
В JavaScript свойство length можно задавать
вручную. Представим, имеется вот такой массив из чисел:
let dig = [1, 2, 3, 4, 5];
далее, мы
уменьшаем его длину:
теперь наш
массив содержит только первые три элемента. Если попытаться восстановить длину снова
до 5:
то можем
убедиться, что последние два элемента уже не существуют:
Вот так через
свойство length можно обрезать
длину массивов.
Язык JavaScript организован
таким образом, что в массиве могут храниться элементы любого типа. Например:
let ar = [ 'Яблоко', { name: 'Джон' }, true, function() { alert('привет'); } ];
И выведем в
консоль свойство name второго элемента:
console.log( ar[1].name );
Причем, массив
не обязательно записывать на одной строке, можно и так:
let ar = [ 'Яблоко', { name: 'Джон' },
true,
function() { alert('привет'); } ];
Массивы в JavaScript – это особого
вида объекты, которые предназначены для работы с упорядоченными коллекциями
данных и оптимизированы для работы с ними. Здесь ключевое слово –
упорядоченные. Дело в том, что движок JavaScript старается хранить элементы
массива в непрерывной области памяти, один за другим и это один из способов
оптимизации. Но мы можем все это легко нарушить, если не будем рассматривать
массивы именно как массивы. Например, можно создать пустой массив:
а, затем, в
очень дальний индекс запишем какое-либо значение:
Технически так
все будет работать, но оптимизации уже не будет. То есть, работать будет
медленнее. Или, можно сделать даже так:
Так как массив –
это объект, то мы просто создаем свойство zero со значением null. Оптимизации
здесь тоже не будет. Наконец, заполняя массив с конца:
digits[100] = 100;
digits[99] = 99;
…
мы тоже теряем
оптимизацию. Во всех этих случаях движок JavaScript будет полагать,
что мы работаем с массивом как с обычным объектом и оптимизация будет
отключена. Поэтому, если уж вы решили использовать массив, то используйте его
по назначению, заполняйте однотипными значениями по порядку и используйте
встроенные методы для обработки его элементов.
Перебор элементов массива
Один из распространенных
способов перебора элементов массива мы только что видели – это цикл for:
Например, для
массива:
let fruits = ["Яблоко", "Апельсин", "Груша"];
перебрать его
элементы можно так:
for(let i=0;i < fruits.length; ++i)
console.log( fruits[i] );
мы увидим все
значения элементов. Но есть и второй новый способ перебора с помощью цикла for of:
for(let value of fruits)
console.log( value );
Эта
запись короче, но имеет свои особенности: значения массива копируются в
переменную value, то есть,
внутри цикла мы имеем дело не с самими значениями массива fruits, а с их
копиями. Например, из-за этого мы не можем менять значения элементов массива
внутри такого цикла:
for(let value of fruits) {
value = "none";
}
console.log(fruits);
В консоле мы
увидим прежний массив. А вот через первый цикл так делать можно:
for(let i=0;i < fruits.length; ++i)
fruits[i] = "none";
Преимуществом
цикла for of является его
оптимизация под массивы. В частности, он работает в 10-100 раз быстрее цикла for in, который мы
рассматривали ранее, для перебора свойств объекта. Формально, мы могли бы
использовать и его:
for(let key in fruits)
console.log( fruits[key] );
Но это будет
медленнее и к тому же там мы будем перебирать все публичные ключи массива, а не
только целочисленные, которые являются индексами элементов массива. В общем,
вывод такой. Нужно перебрать массив, используйте или обычный цикл for или цикл for of.