Массивы в JavaScript
В этой статье мы рассмотрим стандартные JavaScript массивы с числовыми индексами. Массивы объявляются с помощью квадратных скобок:
var fruits = ["Apple", "Orange", "Donkey"]
Чтобы извлечь элемент, поместите его индекс в квадратные скобки. Первый индекс 0:
var fruits = ["Apple", "Orange", "Donkey"]
alert(fruits[0])
alert(fruits[1])
alert(fruits[2])
Мы также можем получить длину массива JavaScript:
var fruits = ["Apple", "Orange", "Donkey"]
alert(fruits.length)
Упс! Мы создали массив с двумя фруктами и ослом. Теперь нам нужно удалить осла.
- Работа с массивами JS - методы pop и push
- Работа с массивами JS - методы shift/unshift
- Работа с массивами JS - перебор массива
- Работа с массивами JS - join и split
- Работа с массивами JS - использование length для обрезки массива
- Работа с массивами JS - array представляет собой объект, что из этого следует
- Работа с массивами JS - нечисловые ключи массива
- Работа с массивами JS - разреженные массивы, описание length
- Работа с массивами JS - удаление из массива
- Работа с массивами JS - метод slice
- Работа с массивами JS - метод reverse
- Работа с массивами JS- сортировка, метод sort(fn)
Работа с массивами JS - методы pop и push
Метод pop в JavaScript удаляет элемент массива и возвращает его.
В следующем примере показано, как «Осел» извлекается из массива:
var fruits = ["Apple", "Orange", "Donkey"]
alert("Я удаляю "+fruits.pop())
// Теперь у нас только ["Apple","Orange"]
alert("Теперь размер массива: "+fruits.length) // осел удален
Обратите внимание, что pop изменяет сам массив.
Аналог pop - это метод push, который добавляет элемент в массив. Например, мы забыли добавить персик:
var fruits = ["Apple", "Orange"]
fruits.push("Peach");
// теперь у нас есть ["Apple", "Orange", "Peach"]
alert("Последний элемент:"+fruits[fruits.length-1])
Задание для самостоятельного выполнения
- Создайте массив styles с элементами “Jazz”, “Blues”;
- Добавьте значение "Rock'n'Roll";
- Замените второе значение с конца значением "Classic". У вас должен получиться массив: “Jazz”, ”Classic”, ”Rock’n’Roll”. Код должен работать для любой длины массива;
- Извлеките последнее значение из массива и выведите его через alert.
Решение
// 1
var styles = ["Jazz", "Bluez"]
// 2
styles.push("Rock'n'Roll") // или: styles[styles.length] = "Rock'n'Roll"
// 3
styles[styles.length-2] = "Classic"
// 4
alert( styles.pop() )
Работа с массивами JS - методы shift/unshift
Методы shift/unshift работают с концом массива, но вы также можете использовать shift, чтобы сдвинуть элементы вверх (первое значение массива удаляется со сдвигом элементов). Метод unshift позволяет в JavaScript добавить элемент в массив с конца:
var fruits = ["Apple", "Orange"]
var apple = fruits.shift() // теперь у нас остался только ["Orange"]
fruits.unshift("Lemon") // теперь мы имеем ["Lemon", "Orange"]
alert(fruits.length) // 2
И shift, и unshift могут работать с несколькими элементами одновременно:
var fruits = ["Apple"]
fruits.push("Orange","Peach")
fruits.unshift("Pineapple","Lemon")
// теперь массив выглядит так: ["Pineapple", "Lemon", "Apple", "Orange", "Peach"]
Задание для самостоятельного выполнения
Напишите код, чтобы вывести через alert случайное значение из массива arr:
var arr = ["Plum","Orange","Donkey","Carrot","JavaScript"]
Примечание: Код для получения случайного числа от минимального до максимального значения (включительно) следующий:
var rand = min + Math.floor(Math.random()*(max+1-min))
Решение
Нам нужно извлечь случайное число от 0 до arr.length-1 (включительно):
var arr = ["Plum","Orange","Donkey","Carrot","JavaScript"]
var rand = Math.floor(Math.random()*arr.length)
alert(arr[rand])
Работа с массивами JS - перебор массива
В JavaScript перебор массива осуществляется с помощью цикла for:
var fruits = ["Pineapple", "Lemon", "Apple", "Orange", "Peach"]
for(var i=0; i<fruits.length; i++) {
alert(fruits[i])
}
Задание для самостоятельного выполнения
Создайте функцию find(arr,value), которая находит значение в заданном массиве и возвращает его индекс или -1, если значение не найдено.
Например:
arr = [ "test", 2, 1.5, false ]
find(arr, "test") // 0
find(arr, 2) // 1
find(arr, 1.5) // 2
find(arr, 0) // -1
Решение
Возможное решение может выглядеть так:
function find(array, value) {
for(var i=0; i<array.length; i++) {
if (array[i] == value) return i;
}
return -1;
}
Но это неверно, потому что == не определяет разницу между 0 и false.
Более корректно при работе с массивами в JavaScript использовать ===. Кроме того новейший стандарт ES5 содержит функцию Array#indexOf. С ее помощью мы можем определить функцию следующим образом:
function find(array, value) {
if (array.indexOf) return array.indexOf(value)
for(var i=0; i<array.length; i++) {
if (array[i] === value) return i;
}
return -1;
}
var arr = ["a", -1, 2, "b"];
var index = find(arr, 2);
alert(index);
Еще разумнее было бы определить find через условие, чтобы проверить, существует ли метод indexOf.
Задание для самостоятельного выполнения
Создайте функцию filterNumeric(arr), которая принимает массив и возвращает новый массив, содержащий только числовые значения из arr.
Пример того, как это должно работать:
arr = ["a", 1, "b", 2];
arr = filterNumeric(arr);
// теперь arr = [1,2]
Решение
Решение заключается в том, чтобы перебрать массив и добавить значения в новый массив, если они являются числовыми.
Работа с массивами JS - join и split
Иногда нужен быстрый способ преобразовать JavaScript массив в строку. Именно для этого предназначен метод join.
Он объединяет массив в строку, используя заданный разделитель:
var fruits = ["Lemon","Apple","Orange","Peach"];
var str = fruits.join(', ');
alert(str);
Обратное преобразование легко выполняется с помощью метода split:
var fruits = "Apple,Orange,Peach";
var arr = fruits.split(',');
// arr содержит теперь ["Apple", "Orange", "Peach"]
alert(arr[0]);
Задание для самостоятельного выполнения
Объект включает в себя свойство className, которое содержит имена классов, разделенные пробелами:
var obj = {
className: 'open menu'
}
Напишите функцию addClass(obj, cls), которая добавляет класс cls, но только если он не существует:
ddClass(obj, 'new') // obj.className='open menu new'
addClass(obj, 'open') // без изменений (class already exists)
addClass(obj, 'me') // obj.className='open menu new me'
alert(obj.className) //
Решение
Нужно разделить className и цикл на части. Если класс не найден, тогда он добавляется.
Цикл немного оптимизирован для увеличения производительности:
function addClass(elem, cls) {
for(var c = elem.className.split(' '), i=c.length-1; i>=0; i--) {
if (c[i] == cls) return
}
elem.className += ' '+cls
}
var obj = { className: 'open menu' }
addClass(obj, 'new')
addClass(obj, 'open')
alert(obj.className) // open menu new
В приведенном выше примере переменная c определяется в начале цикла, и для ее последнего индекса задается значение i.
Сам цикл обрабатывается в обратном направлении, заканчиваясь условием i>=0. Потому что i>=0 проверить быстрее, чем i. Что в JavaScript ускоряет поиск в массиве.
Работа с массивами JS - использование length для обрезки массива
С помощью свойства length можно обрезать массив следующим образом:
var arr = [0, 1, 2, 3]
alert(arr[2]); // элемент все еще здесь
arr.length = 2; // обрезаем массив до двух элементов (то есть остаются: [0,1])
alert(arr[2]); // нет, элемент уже был обрезан
Вы задаете длину, и браузер обрезает массив.
Работа с массивами JS - array представляет собой объект, что из этого следует
На самом деле в JavaScript Array - это Object, дополненный автоматической установкой длины и специальными методами.
Это отличается от концепции в других языках, где массивы представляют собой непрерывный сегмент памяти. Это также отличается от очереди или стека на основе связанных списков.
Работа с массивами JS - нечисловые ключи массива
Ключи - это числа, но они могут иметь любые имена:
arr = []
arr[0] = 5
arr.prop = 10 // не делайте так
Но делать этого не рекомендуется. Числовые массивы подходят для числовых ключей, а JavaScript ассоциативный массив - для связанных пар ключ-значение. И смешивать их не стоит.
Массивы в JavaScript представляют собой хэш-таблицы с их преимуществами в плане производительности, но и с определенными недостатками.
Например, push/pop работают только с крайними элементами массива, поэтому они невероятно быстры.
push работает только с концом:
var arr = ["My", "array"]
arr.push("something")
alert(arr[1]) // строка "array"
Методы shift/unshift медленные, потому что им нужно изменить нумерацию всего массива. Метод splice также может привести к изменению нумерации:

Таким образом, shift/unshift работают медленнее, чем push/pop. Чем больше массив, тем больше времени занимает в JavaScript сортировка массива.
Задание для самостоятельного выполнения
Какой получится результат? Почему?
arr = ["a", "b"]
arr.push( function() { alert(this) } )
arr[arr.length-1]() // ?
Решение
Поскольку массивы являются объектами, arr<a href="/..">..</a> фактически является вызовом метода объекта, таким как obj<a href="/method">method</a>:
arr[arr.length-1]()
// то же самое что
arr[2]()
// синтаксически это неправильно, но концептуально то же самое:
arr.2()
// переписанное в том же стиле, что и obj.method()
this = arr в таком случае передается функции, поэтому выводится содержимое arr.
arr = ["a", "b"]
arr.push( function() { alert(this) } )
arr[arr.length-1]() // "a","b",функция
Работа с массивами JS - разреженные массивы, описание length
Свойство length позволяет получить не размер массива в JavaScript, а последний индекс + 1. Это важно, если речь идет о разреженных массивах, с "промежутками" в индексах.
В следующем примере мы добавим два элемента в пустые fruits, но значение length останется 100:
var fruits = [] // пустой массив
fruits[1] = 'Peach'
fruits[99] = 'Apple'
alert(fruits.length) // 100 (но элементов в массиве всего 2)
Если вы попытаетесь вывести разреженный массив, браузер выдаст значения пропущенных индексов как пустые элементы:
var fruits = [] // пустой массив
fruits[2] = 'Peach'
fruits[5] = 'Apple'
alert(fruits) // ,Peach,,,Apple (или что-то вроде этого)
Но массив - это объект с двумя ключами. Недостающие значения не занимают места.
Разреженные массивы ведут себя причудливо, когда к ним применяются методы массива. Они понятия не имеют о том, что индексы пропущены:
var fruits = [ ]
fruits[1] = 'Peach'
fruits[9] = 'Apple'
alert( fruits.pop() ) // выталкиваем 'Apple' (на индекс 9)
alert( fruits.pop() ) // выталкиваем не заданный элемент (на индекс 8)
Старайтесь избегать разреженных массивов. Во всяком случае, их методы не будут работать нормально. Вместо этого используйте Object.
Работа с массивами JS - удаление из массива
Как мы знаем, массивы - это объекты, поэтому мы могли бы использовать delete, чтобы удалить значение:
var arr = ["Go", "to", "home"]
delete arr[1]
// теперь arr = ["Go", undefined, "home"]
alert(arr[1]) // не задано
Вы видите, что значение удаляется, но не так, как мы хотели бы, потому что массив содержит незаданный элемент.
Оператор delete удаляет пару ключ-значение, и это все. Естественно, так как массив - это только хэш, позиция удаленного элемента становится undefined.
Чаще всего нам нужно удалить элемент, не оставляя «дыр» между индексами. Существует еще один метод, который поможет нам в этом.
Метод splice
Метод splice может удалять элементы и заменять их в JavaScript многомерных массивах. Его синтаксис:
arr.splice(index, deleteCount[, elem1, ..., elemN])
Удаляет элемент deleteCount, начиная с index, а затем вставляет на его место elem1, ..., elemN.
Давайте рассмотрим несколько примеров:
var arr = ["Go", "to", "home"]
arr.splice(1, 1) // удалить 1 элемент, начиная с индекса 1
alert( arr.join(',') ) // ["Go", "home"] (1 элемент удален)
Таким образом, вы можете использовать splice, чтобы удалить один элемент из массива. Номера элементов массива сдвигаются, чтобы заполнить пробел:
var arr = ["Go", "to", "home"]
arr.splice(0, 1) // удаляем 1 элемент, начиная с индекса 0
alert( arr[0] ) // "to" стал первым элементом
В следующем примере показано, как заменять элементы:
var arr = ["Go", "to", "home", "now"];
// remove 3 first elements and add two
arr.splice(0, 3, "Come", "here")
alert( arr ) // ["Come", "here", "now"]
Метод splice возвращает массив удаленных элементов:
var arr = ["Go", "to", "home", "now"];
// удаляем 2 первых элемента
var removed = arr.splice(0, 2)
alert( removed ) // "Go", "to" <-- массив удаленных элементов
splice может вставлять элементы, задайте 0 для deleteCount.
var arr = ["Go", "to", "home"];
// со второй позиции
// удаляем 0
// и вставляем "my", "sweet"
arr.splice(2, 0, "my", "sweet")
alert( arr) // "Go", "to", "my", "sweet", "home"
Данный метод также может использовать отрицательный индекс, который отсчитывается с конца массива:
var arr = [1, 2, 5]
// для элемента -1 (предпоследнего)
// удаляем 0 элементов,
// и вставляем 3 и 4
arr.splice(-1, 0, 3, 4)
alert(arr) // 1,2,3,4,5
Задание для самостоятельного выполнения
Объект содержит свойство className, в котором содержатся имена классов, разделенные пробелами:
var obj = {
className: 'open menu'
}
Напишите функцию removeClass(obj, cls), которая удаляет класс cls, если он задан:
removeClass(obj, 'open') // obj.className='menu'
removeClass(obj, 'blabla') // без изменений (класса для удаления не существует)
Решение
Нужно разделить className на части и перебрать эти части через цикл. Если найдено совпадение, оно удаляется из JavaScript массива объектов, а затем добавляется обратно в конец.
Немного оптимизируем это:
function removeClass(elem, cls) {
for(var c = elem.className.split(' '), i=c.length-1; i>=0; i--) {
if (c[i] == cls) c.splice(i,1)
}
elem.className = c.join(' ')
}
var obj = { className: 'open menu' }
removeClass(obj, 'open')
removeClass(obj, 'blabla')
alert(obj.className) // menu
В приведенном выше примере переменная c задана в начале цикла, и для i задан ее последний индекс.
Сам цикл выполняется в обратном направлении, заканчиваясь условием i>=0. Это сделано потому, что i>=0 проверяется быстрее, чем i. Что ускоряет поиск свойства в c.
Работа с массивами JS - метод slice
Можно извлечь часть массива с помощью метода slice(begin[, end]):
var arr = ["Why", "learn", "JavaScript"];
var arr2 = arr.slice(0,2) // принимает 2 элемента, начиная с 0
alert(arr2.join(', ')) // "Why, learn"
Обратите внимание, что этот метод не изменяет в JavaScript количество элементов в массиве, а копирует его часть.
Можно опустить второй аргумент, чтобы получить все элементы, начиная с определенного индекса:
var arr = ["Why", "learn", "JavaScript"];
var arr2 = arr.slice(1) // принимает все элементы, начиная с 1
alert(arr2.join(', ')) // "learn, JavaScript"
Метод поддерживает отрицательные индексы, так же, как String#slice.
Работа с массивами JS - метод reverse
Еще один полезный метод - reverse. Предположим, я хочу получить последнюю часть домена, например, “com” от “my.site.com”. Вот как это можно сделать:
var domain = "my.site.com"
var last = domain.split('.').reverse()[0]
alert(last)
Обратите внимание, что JavaScript массивы поддерживают сложный синтаксис (reverse()[0]) для вызова метода, а затем извлечения элемента из полученного массива.
Вы можете создавать более длинные вызовы, например, reverse()<a href="/0%5D%5B1">0][1</a>[5]..., синтаксис языка позволяет это.
Работа с массивами JS- сортировка, метод sort(fn)
Метод sort() сортирует массив, не изменяя количество элементов:
var arr = [ 1, 2, 15 ]
arr.sort()
alert( arr ) // 1, 15, 2
Запустите приведенный выше код. Вы получите порядок 1, 15, 2. Это потому, что метод преобразует все в строку и использует по умолчанию лексикографический порядок.
Чтобы сделать метод «умнее», нам нужно передать в него пользовательскую функцию сравнения. Она должна принимать два аргумента и возвращать 1, 0 или -1:
function compare(a, b) {
if (a > b) return 1
else if (a < b) return -1
else return 0
}
var arr = [ 1, 2, 15 ]
arr.sort(compare)
alert( arr ) // 1, 2, 15
Теперь все работает правильно.
Задание для самостоятельного выполнения
Создайте функцию ageSort(people) для сортировки массива объектов людей по возрасту:
var john = { name: "John Smith", age: 23 }
var mary = { name: "Mary Key", age: 18 }
var bob = { name: "Bob-small", age: 6 }
var people = [ john, mary, bob ]
ageSort(people) // теперь люди должны быть отсортированы в таком порядке [ bob, mary, john ]
Выведите имена людей после сортировки JavaScript двумерного массива.
Решение
Нужно использовать Array#sort и пользовательское сравнение:
function ageCompare(a, b) {
if (a.age > b.age) return 1
else if (a.age < b.age) return -1
return 0
}
function ageSort(people) {
people.sort(ageCompare)
}
// проверьте это
var john = { name: "John Smith", age: 23 }
var mary = { name: "Mary Key", age: 18 }
var bob = { name: "Bob-small", age: 6 }
var people = [ john, mary, bob ]
ageSort(people)
// проверьте порядок
for(var i=0; i<people.length; i++) {
alert(people[i].name)
}
Более короткий вариант
Функция сравнения может быть короче. Альтернативное решение:
people.sort(function(a,b) { return a.age - b.age })
Оно работает, так как нам не нужно возвращать 1 / -1 / 0, будут работать положительные или отрицательные числа.
Работа с массивами JS - подробнее об определении массива
new Array()
В JavaScript объявление массива можно осуществить с помощью другого синтаксиса:
var arr = Array("Apple", "Peach", "etc")
Он используется редко только потому, что квадратные скобки [] короче.
Также существует вероятность того, что new Array, вызываемый с одним числовым аргументом, создаст массив заданной длины с неопределенными элементами:
var arr = new Array(2,3) // Ок, мы имеем [2, 3]
arr = new Array(2) // получили ли мы [2] ?
alert(arr[0]) // нет! мы получили [undefined, undefined]
В приведенном выше примере мы получили undefined, потому что new Array(number) создает пустой массив с параметром length равным number.
Это может быть весьма неожиданно. Но если вы знаете об этой особенности, вы можете использовать new Array(number), например, так:
var indent = new Array(5).join('a') // aaaa (4 элемента)
Это оптимизированный способ повторить строку.
Многомерный массив JS
Массивы в JavaScript могут хранить любой тип данных:
var arr = ["My", "Small array", true, {name:'John'}, 345]
alert(arr[1]) // Small array
Это можно использовать для создания многомерных массивов:
var matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
alert(matrix[1][1]) // центральный элемент
Заключение
Это все, что касается углубленного определения JavaScript массивов.
Мы рассмотрели:
- Как объявляется массив, два различных синтаксиса;
- Как добавлять, заменять, удалять элементы массива;
- Как перебрать массив;
- Как разбить строку на массив, а затем собрать ее снова;
- Сравнение Array и Object в JavaScript.
Этого должно быть достаточно в 95% случаев. Чтобы узнать о других методах, обратитесь к Руководству по массиву на Mozilla.