Learn JavaScript

slice и splice в JavaScript: копия vs изменение массива

slice и splice звучат похоже, но делают разные вещи.

  • slice - возвращает часть массива (копию) и не изменяет исходный массив
  • splice - удаляет/вставляет элементы и изменяет исходный массив

Это один из самых важных моментов в работе с массивами.

slice: взять кусок массива без изменений

Синтаксис:

arr.slice(start, end)
  • start - индекс, с которого начинать (включительно)
  • end - индекс, на котором остановиться (не включительно)
  • если end не указан, берется до конца

Пример: часть массива

const items = ["a", "b", "c", "d"];

const part = items.slice(1, 3);
console.log(part);  // ["b", "c"]
console.log(items); // ["a", "b", "c", "d"]

Копия всего массива

slice() без аргументов делает поверхностную копию массива:

const a = [1, 2, 3];
const b = a.slice();

b[0] = 99;

console.log(a); // [1, 2, 3]
console.log(b); // [99, 2, 3]

Отрицательные индексы

Отрицательные индексы считают с конца.

const items = ["a", "b", "c", "d"];

console.log(items.slice(-2));   // ["c", "d"]
console.log(items.slice(0, -1)); // ["a", "b", "c"]

splice: удалить или вставить и изменить массив

Синтаксис:

arr.splice(start, deleteCount, ...itemsToInsert)
  • start - индекс, с которого начать изменения
  • deleteCount - сколько элементов удалить
  • itemsToInsert - что вставить (необязательно)
  • метод возвращает массив удаленных элементов

Удаление элементов

const items = ["a", "b", "c", "d"];

const removed = items.splice(1, 2);
console.log(removed); // ["b", "c"]
console.log(items);   // ["a", "d"]

Удалить один элемент по индексу

const items = ["a", "b", "c"];

const removed = items.splice(1, 1);
console.log(removed); // ["b"]
console.log(items);   // ["a", "c"]

Вставка без удаления

Если deleteCount равен 0, ничего не удаляется, только вставляется.

const items = ["a", "d"];

items.splice(1, 0, "b", "c");
console.log(items); // ["a", "b", "c", "d"]

Замена элементов

Удаление и вставка одновременно - это замена.

const items = ["a", "b", "c", "d"];

items.splice(1, 2, "x", "y");
console.log(items); // ["a", "x", "y", "d"]

Удалить до конца

Если не указать deleteCount, будет удалено все от start до конца.

const items = ["a", "b", "c", "d"];

const removed = items.splice(2);
console.log(removed); // ["c", "d"]
console.log(items);   // ["a", "b"]

Поверхностная копия: важный нюанс

slice делает поверхностную копию. Если внутри массива лежат объекты, копируются ссылки, а не “глубокие” данные.

const a = [{ n: 1 }, { n: 2 }];
const b = a.slice();

b[0].n = 99;

console.log(a[0].n); // 99
console.log(b[0].n); // 99

Копия массива есть, но объекты внутри - те же самые.

Когда что использовать

  • slice подходит, когда нужна копия или подмассив без изменений исходного массива.
  • splice подходит, когда нужно изменить массив: удалить, вставить или заменить элементы по индексу.

Практичное правило: если после операции исходный массив должен остаться прежним - нужен slice (или другие не-мутирующие методы). Если массив должен поменяться - splice.

Частые ошибки

1) Путаница с end в slice

end не включается. Это часто вызывает off-by-one.

const items = ["a", "b", "c", "d"];

console.log(items.slice(1, 2)); // ["b"]

2) Неожиданное изменение массива из-за splice

splice меняет массив. Если исходный массив используется дальше, это может быть проблемой.

const items = ["a", "b", "c"];
const removed = items.splice(1, 1);

console.log(items);   // ["a", "c"]
console.log(removed); // ["b"]

Что стоит запомнить

  • slice не меняет массив и возвращает копию (часть массива).
  • splice меняет массив и возвращает удаленные элементы.
  • slice(start, end) берет элементы от start до end (end не включается).
  • splice(start, deleteCount, ...items) удаляет и/или вставляет элементы.
  • slice копирует массив поверхностно: вложенные объекты остаются общими по ссылке.