Методы работы с массивами в JavaScript

#js

Давайте разберёмся с массивами (объектами Array), какие у них есть методы и как ими пользоваться.

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

let myArray = [];
// эквивалентно:
myArray = new Array();

Если мы не создавали массив, а получили переменную извне, то нужно проверить является ли она массивом.

А также иногда бывает полезно проверить переменную на существование проверив её тип, чтобы избежать ошибки вроде Uncaught ReferenceError: myArray is not defined:

if (
  typeof myArray === 'object' &&
  Array.isArray(myArray)
) {
  console.log(true);
}

Добавление элементов в массив

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

let myArray = [1, 2, 3];

Либо с помощью метода push:

let myArray = [];

myArray.push(1);
myArray.push(2);
myArray.push(3);
// [1, 2, 3]

// эквивалентно:
myArray = [];
myArray.push(1, 2, 3);
// [1, 2, 3]

Либо с помощью метода unshift. В отличие от метода push, метод unshift добавляет элементы в начало массива:

let myArray = [];

myArray.unshift(3);
myArray.unshift(2);
myArray.unshift(1);
// [1, 2, 3]

// или сделаем то же самое, но короче:
myArray = [];
myArray.unshift(1, 2, 3);
// [1, 2, 3]

А ещё массив можно создать из строки:

let myString = "1,2,3";
let myArray = myString.split(',');
// ["1", "2", "3"]

Методы чтения

Получить элемент можно по индексу:

let myArray = [1, 2, 3];

myArray[0]; // 1
myArray[myArray.length - 1]; // 3

Метод pop возвращает последний элемент массива и удаляет его из массива, т. о. следующий вызов pop вернёт уже предпоследний элемент и так до самого начала, а на пустом массиве pop возвращает undefined.

let myArray = [1, 2, 3];

while (myArray.length) {
    console.log(myArray.pop());
}

// 3
// 2
// 1

Метод shift работает так же как pop, только возвращает элемент из начала массива.

let myArray = [1, 2, 3];

while (myArray.length) {
    console.log(myArray.shift());
}

// 1
// 2
// 3

При этом методы push и pop работают быстрее чем методы shift и unshift, т. к. методы shift и unshift перестраивают индексы всех элементов.

Размер массива

У массивов есть только одно свойство: length - количество элементов, а точнее последний индекс + 1.

Укоротить или очистить массив можно просто обновив свойство length:

let myArray = [1, 2, 3];

myArray.length = 2;
// [1, 2]

myArray.length = 0;
// []

Если заполнить в массиве индекс больший чем следующий за последним, то в массиве образуются пустые элементы:

let myArray = [1, 2, 3];
myArray[10] = 4;
// [1, 2, 3, empty × 7, 4]

Так работает, из-за того, что массивы созданы для работы с упорядоченными числовыми индексами. Для остальных случаев лучше подойдёт обычный объект {}.

Изменение элемента

Заменить элемент можно по его индексу:

myArray = [1, 2, 3];

myArray[0] = 'first';

// ["first", 2, 3]

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

Поэтому кроме элементов массива в переменной можно хранить любые свойства:

let myArray = [1, 2, 3];

myArray.state = 'new';
myArray.createdAt = new Date();

Перебирающие методы

Обойти элементы массива можно с помощью for:

let myArray = [1, 2, 3];
let index;

for (
  index = 0;
  index < myArray.length;
  index++
) {
  console.log(myArray[index]);
}

// 1
// 2
// 3

Или с помощью метода forEach(callback[, thisArg]). Аргумент thisArg (если задан) доступен в callback как this.

let myArray = [1, 2, 3];

myArray.forEach(
  (currentValue, index, array) => {
    console.log(
      'index', index,
      'currentValue', currentValue
    );
  }
);
// index 0 currentValue 1
// index 1 currentValue 2
// index 2 currentValue 3

Метод filter(callback[, thisArg]) возвращает массив, состоящий из прошедших проверку элементов.

let myArray = [1, 2, 3];

myArray.filter(
  (currentValue, index, array) => {
    return currentValue > 2;
  }
);
// [3]

Метод map(callback[, thisArg]) применяет callback к каждому элементу массива.

let myArray = [1, 2, 3];

myArray.map(
  (currentValue, index, array) => {
    return currentValue * 2;
  }
);
// [2, 4, 6]

Метод reduce(callback[, initialValue]) выполняет callback к каждому элементу массива, передавая в callback переменную-аккумулятор (первый аргумент функции callback). Начальное значение переменной-аккумулятора - initialValue.

let myArray = [1, 2, 3];

myArray.reduce(
  (previousValue, currentValue, index, array) => {
    return previousValue + currentValue;
  },
  0
);
// 6

Метод reduceRight то же самое что и reduce, только справа-налево.

Проверки

Метод every(callback[, thisArg]) проверяет все элементы с помощью callback, возвращает результат проверки всех элементов.

let myArray = [1, 2, 3];

myArray.every(
  (currentValue, index, array) => {
    return currentValue > 0;
  }
);
// true

myArray.every(
  (currentValue, index, array) => {
    return currentValue > 2;
  }
);
// false

Метод some(callback[, thisArg]) проверяет подходит ли хотя бы один элемент под условие callback.

let myArray = [1, 2, 3];

myArray.some(
  (currentValue, index, array) => {
    return currentValue > 2;
  }
);
// true

myArray.some(
  (currentValue, index, array) => {
    return currentValue > 3;
  }
);
// false

Операции с элементами

Метод splice(start, deleteCount[, item1[, item2[, ...]]]) (не путать со slice) удаляет из массива указанную часть элементов, либо заменяет на новые элементы. При этом возвращает удалённую часть.

let myArray;
let deletedPart;

myArray = [1, 2, 3, 4, 5];
// начиная с индекса 3
// удаляем все остальные элементы до конца
deletedPart = myArray.splice(3);
console.log(deletedPart);
// [4, 5]
console.log(myArray);
// [1, 2, 3]

myArray = [1, 2, 3, 4, 5];
// начиная с индекса 1 удаляем 2 элемента
deletedPart = myArray.splice(1, 2);
console.log(deletedPart);
// [2, 3]
console.log(myArray);
// [1, 4, 5]

myArray = [1, 2, 3, 4, 5];
// удаляем 2 последних элемента
deletedPart = myArray.splice(-2);
console.log(deletedPart);
// [4, 5]
console.log(myArray);
// [1, 2, 3]

myArray = [1, 2, 3, 4, 5];
// удаляем 1 предпоследний элемент
deletedPart = myArray.splice(-2, 1);
console.log(deletedPart);
// [4]
console.log(myArray);
// [1, 2, 3, 5]

myArray = [1, 2, 3, 4, 5];
// заменить первые 3 элемента на другие
deletedPart = myArray.splice(
  0,
  3,
  'one',
  'two',
  'three'
);
console.log(deletedPart);
// [1, 2, 3]
console.log(myArray);
// ['one', 'two', 'three', 4, 5]

Метод slice([begin[, end]]) (не путать со splice) возвращает часть от массива, не удаляя её из исходного массива.

let myArray = [1, 2, 3, 4, 5];

// без аргументов вернёт копию массива
myArray.slice();
// [1, 2, 3, 4, 5]
// эквивалентно:
myArray.slice(0);
// [1, 2, 3, 4, 5]

// вернёт первые 2 элемента
myArray.slice(0, 2);
// [1, 2]

// вернёт все кроме последнего элемента
myArray.slice(0, -1);
// [1, 2, 3, 4]

// вернёт последние 2 элемента
myArray.slice(-2);
// [4, 5]

Метод concat(value1[, value2[, ...[, valueN]]]) возвращает исходный массив с добавленными новыми элементами.

let myArray = [1, 2, 3, 4, 5];

myArray.concat([4, 3, 2, 1]);
// [1, 2, 3, 4, 5, 4, 3, 2, 1]

myArray.concat([6, 7], [8], 9);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

Метод copyWithin(target, start[, end = this.length]) копирует элементы массива начиная с start (индекс) заканчивая end (не индекс, а уже номер элемента) в исходный массив начиная с target (индекс).

let myArray = [1, 2, 3, 4, 5];

myArray.copyWithin(1, 2, 3);
// [1, 3, 3, 4, 5]

Метод fill(value, start, end = this.length) заполняет значения с start (индекс) по end (номер) значением value.

let myArray = [1, 2, 3, 4, 5];

myArray.fill(7, 0, 3);
// [7, 7, 7, 4, 5]

Метод flat(depth = 1) поднимает элементы вложенных массивов в исходный массив погружаясь во вложенные массивы на глубину depth.

let myArray = [1, [2], [[3]]];

myArray.flat(); // [1, 2, [3]]
// эквивалентно:
myArray.flat(1); // [1, 2, [3]]

myArray.flat(2); // [1, 2, 3]

Метод flatMap(callback[, thisArg]) выполняет callback к элементам исходного массива, а после этого поднимает элементы вложенных массивов в исходный массив погружаясь во вложенные массивы на глубину 1. Т. о. этот метод объединяет функционал map и flat.

let myArray = [1, 2, 3, [4], [[5]]];

myArray.flatMap(
  (currentValue, index, array) => {
    if (typeof currentValue === 'number') {
      return currentValue * 2;
    }

    return currentValue;
  }
);
// [2, 4, 6, 4, [5]]

Метод reverse меняет порядок элементов на обратный.

let myArray = [1, 2, 3];

myArray.reverse();
// [3, 2, 1]

Метод sort([compareFunction]) сортирует массив. Обновляет исходную переменную, а не только возвращает новый результат.

let myArray = [3, 1, 2];

myArray.sort();
// [1, 2, 3]

myArray.sort((a, b) => {
  if (a === b) {
    return 0;
  }

  if (a < b) {
    return 1;
  }

  return -1;
});
// [3, 2, 1]

Поиск

Получить индекс элемента по содержимому можно с помощью метода indexOf(searchElement[, fromIndex = 0]):

let myArray = [1, 2, 3];

myArray.indexOf(1);
// 0

myArray.indexOf(2);
// 1

myArray.indexOf(3);
// 2

myArray.indexOf(4);
// -1 - не найдено

Метод lastIndexOf(searchElement[, fromIndex = this.length]) делает то же самое, что и indexOf, только ищет справа-налево.

Метод find(callback[, thisArg]) возвращает значение первого элемента, для которого callback вернул true. Если callback вернул false для всех элементов, то метод вернёт undefined.

let myArray = [1, 2, 3, 4, 5];

myArray.find(
  (currentValue, index, array) => {
    return currentValue > 1;
  }
);
// 2

Метод findIndex(callback[, thisArg]) возвращает индекс первого элемента, для которого callback вернул true. Если callback вернул false для всех элементов, то метод вернёт -1.

let myArray = ['one', 'two'];

myArray.findIndex(
  (currentValue, index, array) => {
    return currentValue.indexOf('w') !== -1;
  }
);
// 1

Метод includes(value) определяет входит ли в массив значение value.

let myArray = [1, 2, 3];

myArray.includes(3); // true
myArray.includes(4); // false

Преобразование в строку

Метод join([separator = ',']) объединяет массив в строку.

let myArray = [1, 2, 3];

myArray.join();
// '1,2,3'
myArray.join('');
// '123'
myArray.join('test');
// '1test2test3'

Метод toLocaleString возвращает строковое представление массива, разделяя элементы локале-зависимой строкой.

let myArray = [1, 2, 3];

myArray.toLocaleString();
// '1,2,3'

Метод toString возвращает строковое представление массива.

let myArray = [1, 2, 3];

myArray.toString();
// '1,2,3'

Итераторы

Метод entries возвращает итератор.

let myArray = ['one', 'two'];

let myIterator = myArray.entries();

myIterator.next();
// {value: [0, "one"], done: false}

myIterator.next();
// {value: [1, "two"], done: false}

myIterator.next();
// {value: undefined, done: true}

Метод keys возвращает итератор по индексам.

let myArray = ['one', 'two'];

let myIterator = myArray.keys();

myIterator.next();
// {value: 0, done: false}

myIterator.next();
// {value: 1, done: false}

myIterator.next();
// {value: undefined, done: true}

Метод values возвращает итератор по значениям.

let myArray = ['one', 'two'];

let myIterator = myArray.values();

myIterator.next();
// {value: "one", done: false}

myIterator.next();
// {value: "two", done: false}

myIterator.next();
// {value: undefined, done: true}

Поддержка

Для работы методов Array.isArray, indexOf, forEach, map, filter и пр. в древних браузерах понадобится подключить es5-shim.

Для корректной работы методов copyWithin, entries, fill, find, findIndex, keys, values, indexOf в некоторых браузерах понадобится подключить es6-shim.

Или вместо es5-shim и es6-shim можно подключить @babel/polyfill.