Tło komputera stacjonarnego i pisanie hologramów formuły Koncepcja edukacji podwójnej ekspozycji

Metody slice i splice w JavaScript – czym się różnią?

11 min. czytania

Metody slice() i splice() w JavaScript mają podobne nazwy, ale służą do zupełnie innych celów: slice() tworzy nową tablicę na podstawie fragmentu istniejącej, nie modyfikując oryginału, natomiast splice() modyfikuje tablicę w miejscu, usuwając i/lub dodając elementy.

Zapamiętaj: slice() nie zmienia źródła, a splice() je zmienia.

1. Dlaczego slice i splice tak często się mylą?

Obie metody działają podobnie na pierwszy rzut oka, bo:

  • działają na tablicach JavaScript,
  • operują na indeksach elementów,
  • pozwalają „wyciąć” fragment tablicy.

Różnica jest jednak fundamentalna:

  • slice() – kopiuje fragment tablicy i zwraca go jako nową tablicę, nie zmieniając oryginalnej;
  • splice() – modyfikuje oryginalną tablicę, usuwając i/lub dodając elementy od wskazanego indeksu; zwraca tablicę elementów usuniętych.

To rozróżnienie ma duże znaczenie w kontekście:

  • architektury aplikacji (mutowalne vs niemutowalne struktury danych),
  • projektowania komponentów UI,
  • stabilności interfejsu i tym samym – pośrednio – dostępności (mniej trudnych do odtworzenia błędów w stanie aplikacji).

2. Wspólne cechy slice() i splice()

Zanim przejdziemy do szczegółów, warto zauważyć, co te metody mają wspólnego:

  • są metodami prototypu Array.prototype, czyli wywołujemy je na tablicach, np. numbers.slice(...),
  • operują na indeksach – dodatnie liczone są od początku (0, 1, 2, …), a ujemne od końca tablicy (…, -3, -2, -1),
  • pozwalają pracować z fragmentami tablicy – ale robią to w zupełnie inny sposób.

To wspólne tło często sprawia, że początkujący programiści używają ich zamiennie, co szybko prowadzi do trudnych do znalezienia błędów.

3. slice() – metoda niemutująca

Co robi slice()?

Metoda slice() służy do wyodrębnienia fragmentu tablicy i zwrócenia go jako nową tablicę, bez modyfikowania oryginału.

Najważniejsze cechy:

  • zwraca nową tablicę zawierającą elementy od indeksu start (włącznie) do end (wyłącznie),
  • nie zmienia tablicy, na której została wywołana (jest niemutująca),
  • może przyjmować wartości ujemne indeksów – wtedy są liczone od końca.

Sygnatura i parametry

Standardowa sygnatura:

Oto wywołanie z parametrami:

array.slice(start?, end?)

Najważniejsze informacje o parametrach:

  • start – indeks, od którego zaczynamy wycinanie (włącznie),
  • jeśli go nie podamy, przyjmowana jest wartość 0,
  • jeśli jest ujemny, liczymy od końca tablicy,
  • end (opcjonalny) – indeks, do którego wycinamy (bez elementu o tym indeksie),
  • jeśli go nie podamy, wycinamy do końca tablicy,
  • jeśli jest ujemny, również liczymy od końca.

Proste przykłady

Przykład 1 – podstawowe użycie

Przykład w JavaScript:

const numbers = [10, 20, 30, 40, 50];
const part = numbers.slice(1, 4);
console.log(part); // [20, 30, 40]
console.log(numbers); // [10, 20, 30, 40, 50] – bez zmian

slice(1, 4) zwraca elementy o indeksach 1, 2, 3; element 4 jest wyłączony.

Przykład 2 – pomijanie end

Przykład w JavaScript:

const numbers = [10, 20, 30, 40, 50];
const fromIndex2 = numbers.slice(2);
console.log(fromIndex2); // [30, 40, 50]
console.log(numbers); // [10, 20, 30, 40, 50]

Brak parametru end oznacza „do końca tablicy”.

Przykład 3 – indeksy ujemne

Przykład w JavaScript:

const numbers = [10, 20, 30, 40, 50];
const lastTwo = numbers.slice(-2);
console.log(lastTwo); // [40, 50]
const middle = numbers.slice(1, -1);
console.log(middle); // [20, 30, 40]

Indeksy ujemne liczone są od końca tablicy.

slice() jako sposób na kopiowanie tablicy

Jeżeli wywołamy slice() bez argumentów, otrzymamy płytką kopię całej tablicy.

Przykład w JavaScript:

const original = ['a', 'b', 'c'];
const copy = original.slice();
copy.push('d');
console.log(original); // ['a', 'b', 'c']
console.log(copy); // ['a', 'b', 'c', 'd']

To popularny sposób na stworzenie niemutowalnej kopii (np. do pracy w stylu „immutable”).

Typowe zastosowania slice()

W praktyce slice() stosuje się m.in. gdy:

  • potrzebujemy fragmentu danych bez zmiany oryginalnej tablicy (np. paginacja: items.slice(offset, offset + limit)),
  • chcemy skopiować tablicę (np. do dalszego przetwarzania lub logowania historii),
  • pracujemy w stylu funkcyjnym lub w bibliotekach preferujących niemutowalne struktury (np. React, Redux – to praktyczna konwencja, a nie cecha samego języka),
  • chcemy wyliczyć „widok” danych (np. filtr + slice) bez ingerencji w źródło.

4. splice() – metoda mutująca

Co robi splice()?

Metoda splice() służy do dodawania, usuwania lub zastępowania elementów w tablicy, modyfikując ją bezpośrednio.

Najważniejsze cechy:

  • działa w miejscu – zmienia oryginalną tablicę,
  • może usuwać i dodawać elementy w dowolnym miejscu tablicy,
  • zwraca nową tablicę zawierającą usunięte elementy (może być pusta),
  • obsługuje indeksy ujemne, liczone od końca.

Sygnatura i parametry

Standardowa sygnatura:

Oto wywołanie z parametrami:

array.splice(start, deleteCount?, ...itemsToAdd)

Najważniejsze informacje o parametrach:

  • start – indeks, od którego zaczynamy modyfikację,
  • jeśli jest ujemny, liczymy od końca tablicy,
  • deleteCount (opcjonalny) – ile elementów usunąć od indeksu start,
  • jeśli deleteCount nie zostanie podany, usuwane są wszystkie elementy od start do końca tablicy,
  • jeśli wynosi 0, żaden element nie jest usuwany – można tylko dodawać,
  • ...itemsToAdd – dowolna liczba elementów do wstawienia w miejscu usuniętych; każdy kolejny argument jest kolejnym dodanym elementem.

Usuwanie elementów

Przykład 1 – usunięcie kilku elementów

Przykład w JavaScript:

const numbers = [10, 20, 30, 40, 50];
const removed = numbers.splice(1, 2);
console.log(removed); // [20, 30] – usunięte elementy
console.log(numbers); // [10, 40, 50] – oryginalna tablica zmieniona

Tutaj od indeksu 1 usuwamy 2 elementy, czyli 20 i 30.

Przykład 2 – usuwanie do końca tablicy

Przykład w JavaScript:

const numbers = [10, 20, 30, 40, 50];
const removed = numbers.splice(2);
console.log(removed); // [30, 40, 50]
console.log(numbers); // [10, 20]

Brak deleteCount oznacza usunięcie od start (2) do końca tablicy.

Dodawanie elementów

Przykład 3 – wstawienie elementów bez usuwania

Przykład w JavaScript:

const letters = ['a', 'd'];
letters.splice(1, 0, 'b', 'c');
console.log(letters); // ['a', 'b', 'c', 'd']

deleteCount = 0, więc nic nie usuwamy, a pod indeks 1 wstawiamy 'b' i 'c'.

Zastępowanie elementów

Przykład 4 – podmiana istniejących wartości

Przykład w JavaScript:

const letters = ['a', 'x', 'y', 'd'];
const removed = letters.splice(1, 2, 'b', 'c');
console.log(removed); // ['x', 'y']
console.log(letters); // ['a', 'b', 'c', 'd']

Usuwamy 2 elementy od indeksu 1 i w ich miejsce wstawiamy dwa nowe.

Indeksy ujemne

Przykład w JavaScript:

const numbers = [10, 20, 30, 40, 50];
numbers.splice(-2, 1); // start = -2 => indeks 3 (40)
console.log(numbers); // [10, 20, 30, 50]

Ujemny start liczy pozycję od końca tablicy.

Typowe zastosowania splice()

splice() wybieramy, gdy intencją jest modyfikacja istniejącej tablicy, np.:

  • edycja danych w miejscu (usuwanie rekordów, wstawianie nowych, reorganizacja listy),
  • implementacja logiki, gdzie aktualizacja tablicy ma być natychmiast odzwierciedlona przez wszystkie referencje (np. proste skrypty, bez zaawansowanego zarządzania stanem),
  • budowanie struktury danych krok po kroku, gdy mutacje są akceptowalne.

5. slice() vs splice() – porównanie

Poniższa tabela syntetyzuje kluczowe różnice między metodami:

Cechy / pytanie slice() splice()
Czy modyfikuje oryginalną tablicę? Nie – zwraca nową tablicę, oryginał pozostaje bez zmian. Tak – działa „w miejscu”, zmienia oryginalną tablicę.
Co zwraca? Nową tablicę z wybranymi elementami. Tablicę usuniętych elementów (może być pusta).
Główny cel Wyodrębnienie fragmentu tablicy / kopia niemutowalna. Usuwanie, dodawanie, zastępowanie elementów w tablicy.
Typ operacji Niemutująca (nie zmienia źródła). Mutująca (zmienia źródło).
Liczba argumentów 0–2 (start, end). 1–n (start, deleteCount, …elements).
Znaczenie indeksu end Nie wlicza elementu o indeksie end. Brak parametru end; używamy deleteCount.
Możliwość dodawania elementów Nie – tylko odczyt/kopia fragmentu. Tak – można wstawiać dowolną liczbę elementów.
Obsługa indeksów ujemnych Tak – liczone od końca tablicy. Tak – liczone od końca tablicy.
Typowe użycie Paginalizacja, wyświetlanie fragmentu, kopia tablicy. Edycja danych „na miejscu” – usuwanie/insert/replace rekordów.

Jeśli nie chcesz zmieniać oryginalnej tablicy, użyj slice().

Jeśli chcesz ją zmienić (usunąć/dodać elementy), użyj splice().

6. Wpływ na architekturę aplikacji i dostępność

Mutowalność a złożone interfejsy

W większych aplikacjach webowych (SPA, PWA) stan interfejsu jest często przechowywany jako złożone drzewo obiektów i tablic. Używanie metod, które mutują stan (jak splice()), utrudnia śledzenie, kiedy i gdzie dana struktura została zmodyfikowana. To nie jest bezpośrednio opisane w specyfikacji, ale wynika z praktyki projektowej.

Niemutujące metody (jak slice()) ułatwiają pracę, ponieważ:

  • ułatwiają debugowanie (zawsze widzimy „starą” i „nową” wersję),
  • ułatwiają porównywanie stanu przed/po (np. prevState !== nextState),
  • zmniejszają ryzyko nieoczekiwanych efektów ubocznych.

To jest szczególnie istotne w bibliotekach takich jak React czy Redux, gdzie niemutowalność stanu jest ważną konwencją – wynika to z ogólnych zasad tych narzędzi, a nie z samego faktu istnienia slice() i splice().

Stabilność UI a dostępność

Błędy wynikające z niekontrolowanej mutacji tablic (np. usunięcie elementu, ale brak aktualizacji powiązanych struktur) mogą skutkować:

  • nieprawidłowym fokusem klawiatury (focus przeskakuje w nieoczekiwane miejsce),
  • niespójnymi etykietami ARIA lub opisami elementów,
  • niespójnością między treścią wizualną a strukturą DOM, którą odczytuje czytnik ekranu.

Choć same metody slice() i splice() nie są „narzędziami dostępności”, to kontrolowanie mutacji stanu za pomocą odpowiednich metod zmniejsza ryzyko błędów, które bezpośrednio uderzają w użytkowników korzystających z technologii asystujących.

7. Typowe błędy i pułapki

Pomylenie slice ze splice (i odwrotnie)

To najczęstszy błąd. Zobacz, co się dzieje, gdy przez pomyłkę użyjesz splice():

const items = [1, 2, 3, 4];
// Intencja: usunąć element o indeksie 1 bez modyfikowania oryginału
const result = items.splice(1, 1); // BŁĄD: wynik i tablica będą inne niż oczekiwano
console.log(result); //
console.log(items); // [1, 3, 4] – tablica została zmieniona!

Jeśli celem było utworzenie nowej tablicy bez elementu o indeksie 1, lepiej zastosować podejście niemutujące:

Przykład w JavaScript:

const items = [1, 2, 3, 4];
const result = [...items.slice(0, 1), ...items.slice(2)];
console.log(result); // [1, 3, 4]
console.log(items); // [1, 2, 3, 4] – bez zmian

Nieprawidłowe rozumienie parametru end w slice()

W slice(start, end) element o indeksie end jest wykluczony. Przykład:

const numbers = [0, 1, 2, 3, 4];
console.log(numbers.slice(1, 4)); // [1, 2, 3], a nie [1, 2, 3, 4]

To klasyczna pułapka off-by-one.

Zapomnienie, że splice() zwraca usunięte elementy

Początkujący czasem oczekują, że wynik splice() będzie „nową tablicą bez usuniętych elementów”, podczas gdy jest to tablica z elementami usuniętymi. Przykład:

const items = ['a', 'b', 'c'];
const result = items.splice(1, 1); // Wynik: result = ['b'], items = ['a', 'c']

Indeksy ujemne w slice() i splice()

Ujemne indeksy są liczone od końca tablicy. Przykłady użycia:

const numbers = [10, 20, 30, 40];
console.log(numbers.slice(0, -1)); // [10, 20, 30]

W przypadku splice(-1, 1) usuniemy ostatni element:

const numbers = [10, 20, 30, 40];
numbers.splice(-1, 1);
console.log(numbers); // [10, 20, 30]

8. Przykłady praktyczne z perspektywy front‑endu

Paginalizacja listy – idealne dla slice()

Wyobraźmy sobie listę artykułów pobranych z API. Tak można wyliczyć dany „widok” strony:

const articles = [/* ...dużo obiektów... */];
const page = 2;
const perPage = 10;
const start = (page - 1) * perPage;
const end = start + perPage;
const visibleArticles = articles.slice(start, end);

Oryginalna tablica articles pozostaje nietknięta.

visibleArticles to nowa tablica, którą można bezpiecznie przekazać np. do komponentu widoku.

Usuwanie elementu z listy edytowalnej – splice()

Dla prostej listy zarządzanej „ręcznie” mutacja może być świadoma i pożądana:

const todoList = ['Zadanie 1', 'Zadanie 2', 'Zadanie 3'];
function removeTodo(index) {
const removed = todoList.splice(index, 1);
console.log('Usunięto:', removed);
}
removeTodo(1);
console.log(todoList); // ['Zadanie 1', 'Zadanie 3']

Aktualizacja stanu w bibliotece nastawionej na niemutowalność

W środowisku, gdzie nie chcemy mutować stanu (np. React + Redux), możemy stosować slice() i operator rozproszenia:

function removeTodoImmutable(todos, index) {
return [
...todos.slice(0, index),
...todos.slice(index + 1),
];
}
const todos = ['A', 'B', 'C'];
const newTodos = removeTodoImmutable(todos, 1);
console.log(todos); // ['A', 'B', 'C']
console.log(newTodos); // ['A', 'C']

9. Powiązane metody: slice, splice i split

W kontekście nazewnictwa często pojawia się jeszcze jedna metoda: split(). Oto szybkie porównanie:

  • slice() – metoda tablicowa; kopiuje fragment tablicy, nie mutuje oryginału,
  • splice() – metoda tablicowa; dodaje/usuwa elementy, mutuje oryginał,
  • split() – metoda łańcuchów znaków, która dzieli string na tablicę według separatora.

split() przyjmuje separator (np. spację lub przecinek) i zwraca nową tablicę fragmentów tekstu, ale w przeciwieństwie do slice()/splice() jest wywoływana na stringu, nie na tablicy.

10. Wskazówki dla junior developerów

  1. Ucz się rozpoznawać mutację stanu:

    jeśli metoda modyfikuje oryginalną tablicę (jak splice()), używaj jej tylko wtedy, gdy jest to w pełni świadome i pożądane; w złożonych aplikacjach częściej preferuj metody niemutujące (slice(), map(), filter()).

  2. Stosuj slice() do „bezpiecznych” operacji:

    • wyświetlanie fragmentu listy (paginacja, „Pokaż więcej”),
    • kopia tablicy przed modyfikacją (np. do historii zmian),
    • generowanie nowych struktur danych z istniejących.
  3. Stosuj splice() do modyfikacji w miejscu:

    • gdy zarządzasz prostym stanem (np. mały skrypt, brak frameworka),
    • gdy chcesz, aby wszystkie referencje do tablicy widziały tę samą zmianę,
    • gdy edytujesz listy w strukturach danych, w których mutowalność jest dopuszczalna.
  4. Czytelność ważniejsza niż oszczędność znaków:

    czasem bardziej rozbudowane rozwiązanie z slice() i operatorem rozproszenia jest bezpieczniejsze i czytelniejsze niż jedna linijka z użyciem splice(), zwłaszcza gdy kod ma być utrzymywany przez większy zespół.

  5. Uważaj na parametry i ich kolejność:

    slice(start, end)end jest wyłączny.

    splice(start, deleteCount, ...items)deleteCount określa ile usunąć, a dopiero potem podajesz elementy do dodania.