JS для начинающих. Урок 1.12: Массивы

js-arraysВсе переменные, которые раньше встречались вам в этом курсе, содержали только одно значение, но зачастую может встретиться необходимость работать с довольно большими наборами данных. Объявлять переменную для хранения каждого элемента такого набора очень неудобно, а если количество элементов набора может меняться, то это почти непосильная задача. Для решения подобных проблем и упрощения работы с длинными наборами данных и были придуманы массивы.

Объявление массивов

Массив – это сколь угодно длинный (на сколько хватит оперативной памяти) набор нумерованных значений. Эти значения могут быть любого типа, включая массивы. Литерал массива представляет собой набор других литералов разделённых запятой, обрамлённый в квадратные скобки.

[1, 2, 3, 4, 5]; // это массив-литерал
[true, false, 'element', 1, 1.2] // это тоже

Массив также может не содержать ни одного элемента. Такой массив называется пустым и ему соответствует вот такой литерал:

[]; // это пустой массив

Литералом массива можно проинициализировать перемену точно так же, как и любым другим значением.

var array = [1, 2, 3, true, false];

Чтобы включить неопределённый (undefined) элемент в литерал массива достаточно пропустить значение между запятыми.

var arr = [1,,2];
console.log(arr);  // [1, undefined, 2]

Существует и другой синтаксис для создания массивов, он редко используется и имеет множество недостатков, но знать о нём всё же стоит.

var array = new Array(1, 2, 3);

Это то же самое, что

var a = [1, 2, 3];

Если функция-конструтор Array (о том, что такое конструктор, вы узнаете в следующих уроках) не принимает ни одного аргумента, то массив создаётся пустым.

var arr = new Array(); // []

Но при передаче единственного положительного целочисленного аргумента нас ждёт неприятный сюрприз.

var arr = new Array(2);
console.log(arr); // [undefined, undefined]

Если функция-конструктор принимает единственный целочисленный элемент, то массив создаётся заполненным неинициализированными элементами. Длина массива, то есть количество неинициализированных элементов его заполняющих равна значению, переданному в качестве аргумента функции-конструктору.

Я не рекомендую вам использовать для создания массива функцию-конструктор из-за её неоднозначного поведения, к тому же этот синтаксис банально длиннее.

Обращение к элементам массива осуществляется по номеру, при этом самому первому элементу массива соответствует ноль, второму – единица и так далее.

var array = [1, 2, 3, 4];
console.log(array[0]); // 1
console.log(array[3]); // 4

Важно знать, что обращение к элементу массива с индексом больше максимального не вызовет ошибки.

var array = [1, 2, 3, 4];
console.log(array[100500]); // undefined

Несуществующие или неопределённые элементы массива можно проинициализировать.

var array = [];
for (var i = 0; i < 10; i++) {
  array[i] = i;
}
array[11] = 10;
console.log(array); // [0, 1, … ,9, undefined, 10]

Существующие элементы массива можно переопределить.

var arr = [1, 2, 3];
arr[0] = 'one';
arr[1] = 'two';
arr[2] = 'three';
console.log(arr); // ['one', 'two', 'three']

Свойство массива length

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

 // тут всё просто
var arr = [1, 2];
console.log(arr.length); // 2
// а тут начинаются странности
arr[4] = 'something';
console.log(arr.length); // 5
console.log(arr); // [1, 2, undefined, undefined, 'something']

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

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

var arr = [1, 2, 3];
arr.length = 5;
console.log(arr); // [1, 2, 3, undefined, undefined]
console.log(arr.length); // 5

Если присвоить свойству length значение меньше, чем то, которое содержится в нём на данный момент, то последние элементы массива удалятся.

var arr = [1, 2, 3, 4, 5];
arr.length = 3;
console.log(arr); //[1, 2, 3]

Вложенные (многомерные) массивы

Я уже упомянул, что массив может содержать массивы в качестве своих элементов. Такой массив может выглядеть, например так:

[1, [2, 3], [4, 5], 'six'];

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

var arr = [1, [2, 3], [4, 5], 'six'];
 
console.log(arr[1]); // [2, 3]
console.log(arr[1][0]); // 2
console.log(arr[1][1]); // 3

Наиболее интересен вариант, когда массив содержит только массивы одинаковой длины.

var arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];

Такие массивы удобно рассматривать, как таблицу, в которой строки это массивы-элементы.

var arr  = [[1, 2, 3],
	[4, 5, 6],
	[7, 8, 9]];

В таких массивах (назовём их прямоугольными) можно хранить, например, расположение фигур на шахматном поле или для хранения значений, расположенных в ячейках таблицы.
Обращение к элементу вложенного массива производится с указанием номера строки и столбца, где он расположен.

var arr  = [[1, 2, 3],
	[4, 5, 6],
	[7, 8, 9]];
 
// этот элемент расположен в нулевой строке и первом столбце 
var el = arr[0][1];
console.log(el); // 2

Существуют массивы и более глубокой вложенности, но они встречаются намного реже.

var arr = [0, [1, 2, [2, 3]]]
 
console.log(arr[1]); // [1, 2, [2, 3]]
console.log(arr[1][2]); //[2, 3]
console.log(arr[1][2][1]); // 3

Обход массивов

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

for (var i = 0; i < arr.length; i++) {
  // делаем что-то с arr[i]
}

Например, увеличим каждый элемент массива на единицу.

var arr = [0, 1, 2, 3, 4];
for (var i = 0; i < arr.length; i++) {
  arr[i]++;
}
console.log(arr); // [1, 2, 3, 4, 5]

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

var arr = [[1, 2, 3],
	[4, 5]];
 
for (var i = 0; i < arr.length; i++) {
  for (var j = 0; j < arr[i].length; j++) {
    arr[i][j] /= 2;
  }
}
 
console.log(arr[0]); // [0.5, 1, 1.5]
console.log(arr[1]); // [2, 2.5]

На этом на всё. Позднее я познакомлю вас со встроенными методами для работы с массивами. Для использования некоторых из них вам понадобится умение написания собственных функций, поэтому я и вынес эту тему в отдельный урок.

Успехов вам!