Wycinanie fragmentów tekstu pojawia się wszędzie tam, gdzie przetwarzam formularze, kody zamówień, adresy e-mail albo podglądy treści w panelu CMS. W praktyce `js substring` oznacza po prostu użycie metody `substring()` do pobrania wybranego kawałka łańcucha znaków bez zmiany oryginału. W tym tekście pokazuję, jak działa zakres indeksów, czym ta metoda różni się od `slice()` i `substr()`, oraz jakie pułapki najczęściej psują wynik w realnym kodzie.
Najważniejsze zasady pracy z `substring()`
- `substring(start, end)` zwraca fragment od indeksu początkowego do końcowego, ale bez znaku końcowego.
- Jeśli podasz tylko `start`, metoda bierze tekst aż do końca łańcucha.
- Ujemne wartości i `NaN` są traktowane jak `0`, a zamieniona kolejność indeksów nadal daje wynik.
- `slice()` lepiej radzi sobie z ujemnymi indeksami liczonymi od końca.
- `substr()` to legacy API i w nowym kodzie lepiej go nie używać.
- Przy emoji i znakach złożonych indeksy odnoszą się do UTF-16, a nie do „widocznych liter”.
Jak działa metoda i kiedy ma najwięcej sensu
Ja traktuję `substring()` jako prosty i bezpieczny sposób na wycięcie zakresu znaków z tekstu. Pierwszy argument wskazuje początek, drugi koniec, a koniec nie wchodzi do wyniku. Sama metoda nie modyfikuje oryginalnego stringa, tylko zwraca nowy fragment, więc dobrze nadaje się do pracy na danych wejściowych, nazwach plików, identyfikatorach czy krótkich opisach.
const brand = "Garmax.pl";
console.log(brand.substring(0, 6)); // "Garmax"
console.log(brand.substring(7)); // "pl"
Najważniejsza korzyść jest prosta: gdy znam dwa punkty cięcia, nie muszę ręcznie liczyć znaków ani pisać dodatkowej logiki. To właśnie dlatego metoda tak często pojawia się w kodzie frontendowym i w prostych operacjach na stringach po stronie backendu. Kiedy już to mam opanowane, największe znaczenie zaczyna mieć sam układ indeksów.
Jak działają indeksy i dlaczego kolejność ma znaczenie
W stringach liczę od zera, więc pierwszy znak ma indeks `0`, drugi `1`, trzeci `2` i tak dalej. W `substring()` pierwszy parametr oznacza początek, drugi koniec, ale wynik kończy się przed `end`. To drobny szczegół, który potrafi zmienić cały rezultat przy skracaniu kodów, tytułów i opisów.
| Wywołanie | Wynik | Co pokazuje |
|---|---|---|
"Garmax".substring(0, 4) |
"Garm" |
Zakres od początku do indeksu końcowego bez znaku `4`. |
"Garmax".substring(4, 1) |
"arm" |
Argumenty zostają zamienione miejscami, zamiast błędu dostaję fragment. |
"Garmax".substring(4, 4) |
"" |
Ten sam początek i koniec dają pusty string. |
"Garmax".substring(0, 99) |
"Garmax" |
Indeks wykraczający poza długość jest obcinany do końca tekstu. |
Jeśli potrzebuję końcówki, często odwołuję się do `length`, bo to daje czytelny i przewidywalny zapis. Przykład poniżej dobrze pokazuje, jak wyciągnąć ostatnie cztery znaki z numeru zamówienia albo kodu faktury.
const orderId = "ORD-2026-4837";
console.log(orderId.substring(orderId.length - 4)); // "4837"
W praktyce to wygodny wzorzec, ale dopiero przy nietypowych danych widać, gdzie metoda ma swoje ograniczenia.
Najczęstsze pułapki, które psują wynik
Najwięcej błędów widzę wtedy, gdy ktoś zakłada, że `substring()` działa „intuicyjnie”. Ona działa logicznie, ale bardzo dosłownie. Dlatego zawsze sprawdzam cztery rzeczy: czy indeksy nie są ujemne, czy nie mylę `end` z długością, czy wynik `indexOf()` nie jest `-1`, i czy tekst nie zawiera znaków złożonych.
- Ujemne wartości nie oznaczają liczenia od końca, tylko są sprowadzane do `0`.
- `NaN` zachowuje się jak `0`, więc źle sparsowany indeks potrafi dać pozornie poprawny wynik.
- Jeśli `start` i `end` są w odwrotnej kolejności, metoda nadal zwróci fragment, zamiast rzucić błąd.
- `substring()` nie rozumie „widocznych znaków” tak jak człowiek, tylko pracuje na jednostkach UTF-16.
To ostatnie ma znaczenie przy emoji, znakach łączonych i tekstach, w których jeden znak użytkownika może składać się z kilku kodów. W takich przypadkach nie używam `substring()` do „krojenia po oczach”; jeśli naprawdę potrzebuję segmentacji na graphemy, sięgam po `Intl.Segmenter` albo rozwiązanie dopasowane do projektu. Dzięki temu nie kończę z tekstem przeciętym w połowie emoji lub złożonej litery. Kiedy te zasady mam z tyłu głowy, porównanie z innymi metodami staje się dużo prostsze.
Substring, slice i legacy substr nie są tym samym
W codziennej pracy najczęściej wybieram między `substring()` a `slice()`. `substr()` zostawiam w spokoju, bo to rozwiązanie legacy i w nowym kodzie nie ma już dobrego powodu, żeby się do niego przywiązywać. Różnice nie są ogromne, ale przy błędnym wyborze potrafią dać inny wynik niż oczekuję.
| Metoda | Argumenty | Ujemne wartości | Gdy ma sens |
|---|---|---|---|
substring(start, end) |
Początek i koniec zakresu | Są traktowane jak `0` | Gdy chcę prostego zakresu i wolę, żeby odwrócone indeksy nadal coś zwróciły |
slice(start, end) |
Początek i koniec zakresu | Liczą się od końca stringa | Gdy wycinam końcówkę lub pracuję z indeksami liczonymi od tyłu |
substr(start, length) |
Początek i długość | Start może liczyć od końca, ale to legacy API | Nie polecam do nowych projektów |
const label = "Garmax";
console.log(label.substring(4, 1)); // "arm"
console.log(label.slice(4, 1)); // ""
Jeśli potrzebuję zakresu od punktu A do B i dane wejściowe mogą być trochę niechlujne, `substring()` bywa wygodniejsza. Jeśli zależy mi na liczeniu od końca, zwykle wybieram `slice()`. A gdy w starym kodzie widzę `substr()`, traktuję to jako sygnał, że przy najbliższej refaktoryzacji warto przebudować ten fragment. W projektach webowych ta różnica szybko przekłada się na bardzo konkretne zastosowania.
Gdzie używam tej metody w projektach webowych
W praktyce `substring()` przydaje mi się głównie wtedy, gdy string trzeba lekko oczyścić, rozciąć albo przygotować do wyświetlenia. To nie jest metoda do wszystkiego, ale w kilku codziennych scenariuszach sprawdza się bardzo dobrze.
Wyciąganie domeny z adresu e-mail
Jeśli pracuję z formularzem kontaktowym albo kontem użytkownika, często chcę odseparować domenę od nazwy skrzynki. W takim układzie najpierw szukam separatora `indexOf()`, a dopiero potem wycinam końcówkę. Zawsze też sprawdzam, czy separator w ogóle istnieje, bo `indexOf()` zwróci `-1`, a wtedy łatwo o błędny wynik.
const email = "biuro@garmax.pl";
const at = email.indexOf("@");
if (at !== -1) {
const domain = email.substring(at + 1); // "garmax.pl"
}
To prosty wzorzec, ale dobrze pokazuje ważną rzecz: `substring()` sama niczego nie wyszukuje, tylko wycina fragment na podstawie indeksów.
Skracanie kodów i identyfikatorów
W e-commerce i panelach administracyjnych często potrzebuję pokazać użytkownikowi tylko końcówkę numeru zamówienia, faktury albo zgłoszenia. Dla takiego scenariusza `substring()` działa dobrze, jeśli długość kodu jest przewidywalna albo wcześniej ją kontroluję.
const orderId = "ORD-2026-4837";
const tail = orderId.substring(orderId.length - 4); // "4837"
Tu da się to zrobić także przez `slice(-4)`, ale sam mechanizm cięcia pozostaje ten sam: ważne jest, żeby świadomie dobrać metodę do tego, jak chcę liczyć indeksy.
Przeczytaj również: Etykiety formularzy () - Jak tworzyć użyteczne formularze?
Przycinanie podglądu treści
Na listach wpisów, kartach produktów i w panelach CMS często potrzebuję krótkiego podglądu tytułu lub opisu. Technicznie najprościej zrobić to przez `substring(0, n)`, ale w warstwie UX wolę uważać, żeby nie ucinać słowa w połowie.
const title = "Jak działa substring w JavaScript";
const preview = title.substring(0, 24) + "...";
W interfejsie wygląda to lepiej, gdy skrócenie odbywa się po spacji, a nie w losowym miejscu. Przy opisach SEO, snippetach i kartach produktowych robi to realną różnicę, bo urwany środek słowa wygląda po prostu gorzej. Z tego powodu prosty filtr decyzji oszczędza mi najwięcej czasu.
Mój szybki filtr decyzji przed wycięciem tekstu
Jeśli mam wybrać metodę bez zastanawiania się przez pół dnia, stosuję bardzo prostą kolejność myślenia. Najpierw pytam, czy potrzebuję zakresu, końcówki, czy może najpierw muszę znaleźć separator.
- `substring()` biorę, gdy znam dwa końce zakresu i chcę prosty, przewidywalny wynik.
- `slice()` wybieram, gdy liczę od końca albo świadomie pracuję na ujemnych indeksach.
- `indexOf()` i `lastIndexOf()` dokładam, gdy muszę najpierw znaleźć separator w tekście.
- `Intl.Segmenter` rozważam, gdy liczę znaki widoczne dla użytkownika, a nie jednostki UTF-16.
- `substr()` omijam w nowych projektach, bo to stara ścieżka, która częściej wprowadza zamieszanie niż pomaga.
To podejście sprawdza się zarówno w małych skryptach front-endowych, jak i w kodzie, który zasila formularze, treści CMS czy e-commerce. Gdy pilnuję semantyki cięcia zanim dotknę indeksów, `substring()` pozostaje wygodnym narzędziem, a nie źródłem trudnych do namierzenia błędów.