Всё только о JavaScript

/ Статьи / Массивы в JavaScript

Объединение массивов

Иногда необходимо объединить несколько массивов в один, содержащий элементы из исходных массивов. Для этого в JavaScript есть метод concat. Он создаёт копию исходного массива, добавляя к нему переданные аргументы, подобно методу push. Однако, в отличие от push, если методу concat передан другой массив, то будут добавлены элементы этого массива, а не сам массив единственным элементом.

Array.prototype.toString = function() {
    return '[' + this.join(', ') + ']';
};
var a = [1, 2, 3];
alert(a.concat(4, 5, 6));      // [1, 2, 3, 4, 5, 6]
alert(a.concat([4, 5], [6]));  // [1, 2, 3, 4, 5, 6]

Однако дальше одного уровня concat аргументы-массивы не разворачивает.

Array.prototype.toString = function() {
    return '[' + this.join(', ') + ']';
};
var a = [1, 2, 3];
alert(a.concat([4, [5], 6]));      // [1, 2, 3, 4, [5], 6]

С разреженными массивами ситуация обстоит ожидаемая: пропуски как из исходного массива, так и из массивов-аргументов, сохраняются.

Array.prototype.toString = function() {
    return '[' + this.join(', ') + ']';
};
var a = [1, , 3];
alert(a.concat([4, , 6]));      // [1, , 3, 4, , 6]

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

Метод slice имеет сигнатуру slice(begin[, end]) и возвращает подмассив исходного массива, начиная с индекса begin и заканчивая индексом end - 1. Чтобы легче запомнить такую странную нумерацию, лучше считать, что передаются индексы не элементов, а "межэлементного пространства".

Индексы элементов:   0 1 2 3 4 5 6 7 8
                    ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
                    | | | | | | | | | |
Индексы для slice:  0 1 2 3 4 5 6 7 8 9

Тогда становится понятно, что ar.slice(0, 1) вернёт только нулевой элемент, а slice(5, 9) — с пятого по восьмой элементы.

var a = [0, 1, 2, 3, 4, 5];
alert(a.slice(0, 2));    // 0,1
alert(a.slice(4, 5));    // 4

Если второй аргумент является отрицательным числом, то отсчёт второго индекса идёт с конца массива.

var a = [0, 1, 2, 3, 4, 5];
alert(a.slice(0, -2));    // 0,1,2,3

Если же второй аргумент не передан вообще, то возвращается копия массива от begin до конца.

var a = [0, 1, 2, 3, 4, 5];
alert(a.slice(3));    // 3,4,5

Клонирование массива

В JavaScript нет нативного метода для клонирования массивов, однако его легко сэмулировать, помня, что concat и slice не меняют исходный массив. Достаточно вызвать метод concat без аргументов или метод slice с единственным аргументом равным 0.

var a = [1, 2, 3];
var b = a.concat();
var c = a.slice(0);
alert(a + ' ; ' + b + ' ; ' + c);    // 1,2,3 ; 1,2,3 ; 1,2,3
alert([a == b, a == c, b == c]);     // false,false,false

Обратите внимание, если в массиве лежат ссылки на объекты, в том числе ссылки на другие массивы, то в новосозданном массиве будут лежать ссылки на те же самые объекты. Поэтому если вы хотите клонировать многомерный массив, то придётся вручную создавать новый массив, после чего перебрать подмассивы исходного массива и клонировать их в новый.

// Клонируется только массив верхнего уровня
var a = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];
var b = a.concat();
alert(a[0][1]);   // 2
alert(b[0][1]);   // 2
b[0][1] = 15;
alert(a[0][1]);   // 15

// Клонируем вложенные массивы
var a = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];
var b = [];
a.forEach(function(subArray) {
    b.push(subArray.concat());
});
alert(a[0][1]);   // 2
alert(b[0][1]);   // 2
b[0][1] = 15;
alert(a[0][1]);   // 2