06. Массивы

Массив — это объект

Массив — это специализированный объект, в котором хранятся пронумерованные (с нуля) значения.

Массив, как объект, имеет встроенное свойство length, содержащее количество элементов массива. Можно назначать массиву (как объекту) любые дополнительные свойства.


var x = [1,2,3];   // Создали массив при помощи литерала
x.type = "числа";  // Создали свойство type и присвоили строку "числа"
x["type"] == "числа"; // Равно true
x.sum = function () // Создали свойство sum и присвоили ему ссылку
        {           // на функцию, заданную литералом. Сама функция 
          var s=0;  // сохраняется где-то в памяти.
          for (var i=0; i<this.length; i++) s+= this[i];
          return s;
        }
x.sum(); // Равно 6 (вызов метода sum)
x["sum"](); // Равно 6 (вариант вызова метода sum)

Создание массива при помощи литерала

Создать массив можно при помощи литерала:


var empty = []; // Пустой массив, empty.length равно 0
var numbers = [152,556,0]; // Массив из трёх чисел, 
                           // numbers.length равно 3
var p = [1,true,"Роботландия"]; // Массив, содержащий значения разных 
                                //типов, p.length равно 3

Напоминаю, что в переменных empty, numbers, p сохраняются не сами массивы, а ссылки на них. А массивы создаются интерпретатором JavaScript где-то в памяти.

Значения в литерале массива не обязаны быть константами:


var s = "кот";
// Создается массив ["котовасия", "поток", 3]
var m = [s+"васия", s.replace(/к/, "п")+"ок", s.length];

Каждый элемент массива может иметь значение любого типа, в частности, быть объектом:


var m = [{x:1,y:2}, function(t){return t*t;}]; // Массив их 2 элементов
var x = m[0].y;   // Равно 2 (доступ к свойству y объекта m[0])
var y = m[1](2);  // Равно 4 (вызов функции m[1])
var z = m.length; // Равно 2

Элементы можно задавать с пропусками, они получают значение undefined:


var m = [23,,1];  // m[0] -- есть 23
                  // m[1] -- есть undefined
                  // m[2] -- есть 1
                  // m.length -- есть 3

Создание массива при помощи конструктора

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

Как уже отмечалось в заметке 4, в Javascript нет настоящих классов, как в других объектно-ориентированных языках программирования, таких как C++ или Java, но классы можно имитировать при помощи функции-конструктора.

Следующие две строки эквивалентны:


var m = new Array(); // создали пустой массив при помощи конструктора
var m = [];          // создали пустой массив при помощи литерала

Когда применяется литерал, конструктор вместе с оператором new вызываются неявно.

В конструкторе можно указывать значения первых элементов:


var m = new Array(1,"1"+"2",3*2);
m[0] == 1;    // Равно true
m[1] == "12"; // Равно true
m[2] == 6;    // Равно true

Задавать значения с пропусками в конструкторе нельзя:


var m = new Array(23,,1);  // Синтаксическая ошибка

Можно, правда, написать:


var m = new Array(23,undefined,1); 

но такой способ оформления пропусков нерационален.

Вызов конструктора с единственным аргументом задаёт длину массива, и не инициализирует элементы (все элементы undefined):


var m = new Array(3); // m.length -- есть 3
                      // m[0] -- есть undefined
                      // m[1] -- есть undefined
                      // m[2] -- есть undefined

Чтение и запись элементов массива

Доступ к элементам массива для чтения и записи выполняется с помощью оператора [] по формату:

ссылка_на_массив[выражение]


var a = [1,2,3,4];
var x = a[1];  // Равно 2
var x = [1,2,3,4][2];  // Равно 3
a[0] = "кот";
a[a[1]] = 100;
a[2] == 100; // Равно true

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


var a = [1,2,3];
a.length == 3; // Равно true
a[3] = 4;
a.length == 4; // Равно true
a[5] = 100;
a.length == 6; // Равно true
// Теперь массив имеет вид: [1,2,3,4,undefined,100]

Оператор delete не удаляет элемент массива, а сбрасывает его значение в undefined:


var a = [1,2,3];
delete a[1];
// Теперь массив имеет вид: [1,undefined,3]

Длина массива

Свойство length массива всегда на единицу больше самого большего индекса массива, и поддерживается автоматически.


var a = []; // a.length равно нулю
a[99] = 1;  // a.length равно 100

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


var a = new Array(1,2,3); // a.length равно 3
a.length = 2; // Теперь массив стал таким [1,2]
a.length = 4; // Теперь массив стал таким [1,2,undefined,undefined]
a[99] = 0;    // a.length теперь равно 100

Пример

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


function sum(a)
{
  var sum = 0;
  for (var i=0; i<a.length; i++) sum +=  a[i] || 0;
  return sum;
}
var m = [1,2,,,,,,,,,,,,3];
var k = sum(m); // Равно 6

Многомерные массивы

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

Таблицу:

11 12 13
21 22 23
31 32 33

можно задать так:


var m = [
  [11,12,13], // Первая строка
  [21,22,23], // Вторая строка
  [31,32,33]  // Третья строка
        ];

Сформируем таблицу умножения при помощи конструктора Array.


var table = new Array(10);
for (var i=0; i<10; i++) 
{
  table[i] = new Array(10);
  for (var j=0; j<10; j++) table[i][j] = i*j;
}
var x = table[4][2]; // Равно 8

Объекты, подобные массивам

Как говорилось ранее, объект можно рассматривать, как ассоциативный массив, то есть как множество пар «строка:значение».

Если значениям поставить в соответствия строки "0", "1", "2", "3", "4", "5", ..., то с таким объектом можно работать почти как с массивом.


var a = {"0":100, "1":200, "2":300}; // Создаём объект, подобный массиву
a.length = 3;                        // Задаём свойство length

Посмотрим, что у нас получилось.


a[0] == 100; // true
             // Число 0 преобразуется в строку "0" (ибо по контексту
             // требуется строка).
             // a["0"] есть 100 (значение свойства "0")
a[1] == 200; // true
             // Число 1 преобразуется в строку "1" (ибо по контексту
             // требуется строка).
             // a["1"] есть 200 (значение свойства "1")
a[a.length-1] == 300; // true
             // Вычисляется выражение a.length-1 -- результат 2
             // Число 2 преобразуется в строку "2" (ибо по контексту
             // требуется строка).
             // a["2"] есть 300 (значение свойства "2")
a[1]= 500;   // Число 1 преобразуется в строку "1" (ибо по контексту
             // требуется строка). Получается инструкция a["1"] = 500
             // Свойству, ассоциированному со строкой "1" присваивается
             // число 500

Еще один пример. Создадим объект подобный массиву, содержащий квадраты чисел от 0 до 100.


var a = {};  
a.length = 101;            
for (var i=0; i<a.length; i++) a[i] = i*i;         
// Теперь найдём, например, сумму созданных элементов.
var sum = 0;             
for (var i=0; i<a.length; i++) sum += a[i];         

Как видите, с объектом, действительно, можно работать почти как с массивом, если имена его свойств обозначить строками, которые соответствуют обычной нумерации в массиве ("0", "1", "2", "3", "4", "5", ...) и не забыть задать свойство length.

Почему почти? Потому, что наше свойство length не будет автоматически меняться при изменении длины «массива». И потому, что к такому «массиву» нельзя будет применять методы класса Array. В частности, не будут работать методы push и pop, как и все другие, о которых рассказано в разделе Array.

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

Методы массивов

С массивами удобно работать при помощи методов, присутствующих в классе Array.

Заметим, что эти методы будут работать вне зависимости от того, как создан массив, при помощи конструктора Array или при помощи литерала. В последнем случае конструктор Array всё равно вызывается неявно. Заметим также, что эти методы не работают с объектами (не являющимися массивами), в том числе с объектами, подобными массиву.

В разделе Array приводится краткое описание методов класса Array, в разделе задания собраны контрольные задания (с решениями).