javascript массивы

Что такое массивы в JavaScript?

Массив это набор значений, идентифицируемых с помощью индекса.

Обычно под массивы выделяется непрерывный кусок памяти заданной длины. В JavaScript это не так. Массивы в JavaScript это просто объекты с уникальным конструктором и дополнительным набором свойств и методов, наследуемых от Array.prototype. Из-за этого производительность будет немного хуже, однако это компенсируется простотой использования и мощным набором инструментов. В отличие от массиов в других языках программирования, массивы JavaScript очень удобны в использовании – это то, что несомненно сделано правильно.

 

Как создавать массивы в JavaScript?

Давайте начнем с наилучшего способа. В JavaScript существует литеральный синтаксис для создания массива, обычно стоит использовать его.

//создаем новый пустой массив
var a = [];
//добавляем элементы в созданный массив
a[0] = "Bob";
a[1] = "Mary";
a[2] = "Joe";
//либо просто используем push
a.push("Jane");
a.push("Carlos");
//создаем новый массив и определяем несколько элементов
var b = ["Bob", "Mary", "Joe", "Jane", "Carlos"];

Также вы можете использовать синтаксис new Constructor. Кроме того, что вам придется напечатать на 5-9 символов больше (“new” является опциональным), существует более серьезная проблема в неоднозначном смысле:

//создаем новый массив с 8 неопределенными элементами
var a = new Array(8);
//создаем новый массив, содержащий 2 заданных элемента
var b = new Array(8,9);
a.length; //8
b.length; //2
a[0]; //undefined
b[0]; //8

Эти два определения выглядят очень похожими, однако имеют совершенно разные значения. Более того, допустим кто-то захочет изменить второе определение, поскольку теперь ему нужно определить только один элемент, число 8 в массиве b. Вполне вероятно, что он изменит его следующим образом (и кто будет виноват?):

//создаем новый массив с одним заданным элементом
var b = new Array(8); //неверно!

Конечно же, это не то, что требуется. Единственный способ определить массив с одним заданным числом – использовать литеральный синтаксис (квадратные скобки).

 

Есть ли преимущества в использовании синтаксиса new Array?

Да, это значит, что вы можете задать длину массива во время его создания. Но так как JavaScript не требует заранее выделять память под массивы, и их длина может быть изменена в любое время, это является спорным преимуществом. (Некоторые люди отмечают, что webkit оптимизирован для случая с заданной длиной массива – хотя в спецификации ничего про это не сказано)

 

Какие типы данных может содержать массив?

Массив может содержать любой объект или элементарный тип. Несколько типов данных могут одновременно находиться в одном массиве.

 

Как обращаться к элементу массива?

Элементы массива являются обычными свойствами объекта, и к ним можно обращаться также, как и к свойствам. Поскольку идентификаторы свойств всегда являются строками, индекс массива – тоже строка, а не число. Однако, когда вы используете индексную запись (квадратные скобки), чтобы обратиться к свойству, то также может использоваться числовое значение, поскольку оно будет преобразовано интерпретатором в строку. Обращение к элементу массива через точку не будет работать, т.к. идентефикатор свойства не может начинаться с цифры. (К тому же, такое поведение получается из правил свойства объекта, это касается не только массивов).

var a = ["banana", Math.min, 4, "apple"];
a['1']; //min()
a[2]; //4

 

Как делать перебор элементов массива?

Обычно имеет смысл использовать стандартный цикл for:

var a = ["banana", Math.min, 4, "apple"];
for (var i=0; i < a.length; i++) {
    console.log(a[i]);
}

Если массив довольно большой, то вы, возможно, будете обеспокоены дополнительной нагрузкой при обращении к array.length при каждой итерации. Чтобы избежать этого, вы можете определить длину массива заранее:

var a = makeBigArray();
var aLength = a.length;
for (var i=0; i < aLength; i++) {
    console.log(a[i]);
}

Использование выражения for…in не рекомендуется для перебора элементов массива, поскольку вы можете также захватить enumerable свойства из prototype (см. ниже)

 

Какие свойства массива уникальны?

Наиболее важное свойство массива – length (строки и функции также имеют свойство length, однако в массиве length является

В ECMA сказано:
Свойство массива, принадлежащее объекту Array, всегда численно больше, чем имя любого свойства, являющееся индеском массива.

Другими словами, оно вычисляется как: (численное значение последнего индекса) + 1

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

var a = [3,4,1];
a.length; //3
a[20] = 2;
a.length; //21
//элементы с индексами 3-19 автоматически создаются со значением undefined 
a[18]; //undefined

Массивы всегда ограничены снизу нулем. Если вы попытаетесь добавить значение с отрицательным индексом, то вы просто запишите обычное свойство объекта (смотрите также “ассоциативные массивы” ниже)

var a = [];
a[-1] = "giraffe";
a[-1]; //"giraffe"; //т.к. используется обычное свойство объекта
a.length; //0
a.toString(); //""

Вы можете манипулировать содержимым массива, обновляя значение length. Если вы уменшаете свойство массива length, то элементы с индексами больше или равными новой длине масива удаляются (это является единственным способом удалить индексы из массива – вы можете удалить элемент, но при этом удалится лишь значение, а индекс останется на месте – т.е. ваш массив становится “разреженным” = в нем появляются дырки)

var a = [0,1,2,3,4,5,6];
a.length; //7
a.length = 5;
a.toString(); //"0,1,2,3,4"
a[6]; //undefined

И наоборот, если вы увеличиваете свойство length массива на величину n, то в вашем массиве появится n новых элементов со значением undefined. На самом деле, ничего не меняется, кроме длины массива length.

var a = [0,1,2,3,4,5,6];
a.length; //7
a[9]; //undefined
a[59]; //undefined
a.length = 10;
a.toString(); //"0,1,2,3,4,5,6,,,"
a[9]; //undefined
a[59]; //undefined

Существует два дополнительных псевдо-свойства массивов: index и input. Эти свойства появляются в массивах, созданных при помощи регулярных выражений.

 

Какие методы наследуются от Array.prototype?

Оъект Array предоставляет большое количество очень полезных инструментов, очень подробно рассмотрены функции в ECMA5, с большинством которых вы, возможно, знакомы. Следующие методы массивов доступны для всех последних версий браузеров.

concat поверхностно копирует массив и добавляет к нему аргументы

join объединяет элементы массива в строку, разделенные аргументом

shift удаляет и возвращает первый элемент

pop удаляет и возвращает последний элемент

unshift добавляет аргументы в начало массива

push добавляет аргументы в конец массива

reverse изменяет порядок элементов массива, не копируя его

slice поверхностно копирует часть массива – элементы с индекса start до end, не включая end

splice – удаляет указанные элементы из массива, заменяя их опциональными аргументами

sort – сортирует массив, не копируя его, опционально использует функцию сравнения в качестве аргумента

toString вызывает join без аргумента

ECMA5 определяет дополнительный набор функций, которые все уже реализованы основными браузерами, кроме IE<=8 (но реализованы в IE9 preview). Многие из этих новых методов знакомы тем из вас, кто пользуется основными фреймворками JavaScript:

indexOf возвращает индекс первого элемента, равного указанному значению, или -1, если ничего не найдено

lastIndexOf возвращает индекс последнего элемента, равного указанному значению, или -1, если ничего не найдено

every возвращает true, если переданная функция вернет true для каждого элемента массива

some возврадает true, если переданная функция вернет true хотя бы для одного элемента массива

forEach применяет переданную функцию к каждому элементу массива

map создает новый массив, содержащий результаты применения переданной функции к каждому элементу массива

filter создает новый массив, содержащий все элементы, для которых переданная функция вернет true

reduce применяет функцию одновременно к двум значениям массива (слева направо) так, что массив уменьшается до одного значения (замечание: reduce имела другое значение в прошлых версиях Prototype.js)

reduceRight применяет функцию одновременно к двум значениям массива (справа налево) так, что массив уменьшается до одного значения

 

Как узнать является ли объект типом Array?

Это очень частый вопрос. Проблема в том, что когда в JavaScript вы применяете typeof к массиву, то вовращается “object”. Функцию isArray, которая сейчас используется в jQuery и Prototype.js, можно реализовать следующим образом:

function isArray(o) {
  return Object.prototype.toString.call(o) === "[object Array]";
}

 

А что же насчет “Ассоциативных массивов”?

JavaScript не поддерживает ассоциативные массивы (associative arrays). Это общее заблуждение происходит из-за приведенного ниже не численно индексного массива.

var a = new Array();
a['cat'] = 4;
a['spider'] = 8;
a['centipede'] = 100;
a['spider']; //8

На самом деле в этом коде (хотя он и не является некорректным) неправильное использование объекта массив. К массиву не добавляется ни одного элемента (array.length равно 0). Все что мы сделали, так это присвоили свойства обычному объекту – фактически мы создали хэш таблицу.

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

var a = Boolean;
a['cat'] = 4;
a['spider'] = 8;
a['centipede'] = 100;
a['spider']; //8

Более того, создание хэшей над объектом Array потенциально опасно. Если кто-нибудь расширит Array.prototype enumerable свойствами (что, например, можно сделать с помощью библиотеки Prototype.js), то все они будут перечислены в цикле for…in, разрушая вашу логику (или по крайней мере придется использовать неэффективный метод hasOwnProperty).

Создавайте хэши над объектом Object и больше нигде, поскольку по соглашению Object.prototype нельзя расширить.

 

Вы также можете прочитать оригинал данной статьи на английском языке: Understanding Javascript Arrays.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>