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] // Третья строка
];
- m[1] — это второй элемент, массив [21,22,23]
- m[1][2] — это третий элемент второго массива, то есть число 23
Сформируем таблицу умножения при помощи конструктора 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, в разделе задания собраны контрольные задания (с решениями).