Trzy sposoby zapisu stringa
JavaScript daje ci trzy ograniczniki stringów. Dwa są wymienne, trzeci potrafi więcej.
Apostrofy i cudzysłowy dają identyczne stringi: wybierz jeden styl i się go trzymaj (większość nowoczesnych projektów domyślnie używa apostrofów albo zostawia decyzję formaterowi). Backticki tworzą template literal i tu robi się ciekawie: pozwalają na interpolację i obejmują wiele linii.
Pod spodem wszystkie trzy tworzą ten sam prymitywny typ string. Ogranicznik to tylko kwestia składni.
Sekwencje ucieczki i cudzysłowy w środku
Wewnątrz stringa ukośnik wsteczny zaczyna sekwencję ucieczki. Najczęstsze to \n (nowa linia), \t (tabulator), \\ (dosłowny ukośnik wsteczny) oraz \" / \' do wstawienia tego samego cudzysłowu, którym string otwarto:
Większości znaków ucieczki unikniesz, wybierając drugi rodzaj cudzysłowu: 'She said "hi" and left.' nie potrzebuje żadnego ukośnika. Pragmatyzm ponad dogmaty.
Template literals: supermoc backticków
Template literal robi dwie rzeczy, których nie potrafią zwykłe stringi. Po pierwsze, interpoluje wyrażenia przez ${...}:
Wszystko wewnątrz ${...} to wyrażenie JavaScript, a nie tylko nazwa zmiennej. Arytmetyka, wywołania funkcji, operatory trójargumentowe, a nawet inne template literals, wszystko wolno:
Po drugie, template literals obejmują wiele linii bez \n:
Znaki nowej linii w kodzie źródłowym stają się znakami nowej linii w stringu. Przy wszystkim, co jest dłuższe od krótkiej etykiety, backticki to prawie zawsze dobry wybór.
Interpolacja wygrywa z konkatenacją
Zanim pojawiły się template literals, jedynym sposobem na zbudowanie dynamicznego stringa był operator +:
Obie wersje dają identyczny wynik. Template literal czyta się jak zdanie, które buduje, a wersja z + zmusza cię do pilnowania cudzysłowów, spacji i operatorów konkatenacji. Używaj + tylko wtedy, gdy doklejasz coś małego do istniejącego stringa. Przy czymkolwiek dłuższym sięgaj po backticki.
Stringi są niemutowalne
Każda metoda, która wygląda, jakby zmieniała string, w rzeczywistości zwraca nowy:
Jeśli chcesz zachować zmianę, musisz gdzieś przypisać wynik. To pułapka dla początkujących, którzy piszą s.replace("a", "b") i oczekują, że s się zmieni. Nie zmieni się. Stringi w JavaScript są jak liczby: samej wartości nie da się zmienić, można tylko skierować zmienną na nową wartość.
Metody stringów, których naprawdę używasz
Pełne API stringów jest duże. Oto garść metod, po które sięgasz codziennie:
Kilka rzeczy, które warto zapamiętać:
lengthto właściwość, a nie metoda: bez nawiasów.replaceze zwykłym stringiem zamienia tylko pierwsze wystąpienie. Żeby zamienić wszystkie, użyjreplaceAllalbo wyrażenia regularnego z flagąg.slice(start, end)przyjmuje przedział prawostronnie otwarty: znak na pozycjiendnie jest wliczany.- Ujemne indeksy w
sliceliczą się od końca:s.slice(-3)daje ostatnie trzy znaki.
Indeksowanie i przechodzenie po znakach
Stringi zachowują się jak tablice znaków tylko do odczytu. Możesz odwoływać się do nich przez indeks i po nich iterować, ale nie możesz przypisać wartości na danej pozycji:
for...of iteruje po punktach kodowych (code points), co poprawnie obsługuje większość Unicode. Indeksy (s[i]) iterują po jednostkach kodu UTF-16, co potrafi przeciąć na pół emoji i inne znaki spoza BMP. Przy zwykłym tekście oba sposoby są w porządku. Przy treściach wpisywanych przez użytkowników wybierz for...of albo [...s].
Tagged template literals
Jest jeszcze jedna forma, którą warto znać, nawet jeśli rzadko ją piszesz. Otagowany (tagged) template literal wywołuje funkcję, przekazując jej osobno statyczne kawałki stringa i wstawione wartości:
Funkcja tagu decyduje, jak wygląda końcowy string: może escapować HTML, bezpiecznie budować SQL, kompilować CSS albo parsować GraphQL. Ten wzorzec zobaczysz w bibliotekach (styled-components, graphql-tag, lit-html) znacznie częściej, niż sam go napiszesz. Ale gdy potrzebujesz własnego przetwarzania stringów, tagi są najczystszym narzędziem.
Typowe pułapki
Krótka lista rzeczy, na których ludzie się potykają:
- Zapominanie o przypisaniu wyniku metody. Samo
s.trim()nic nie robi. - Łączenie liczby ze stringiem przez
+."Age: " + 30 + 5to"Age: 305", a nie"Age: 35". Template literals omijają ten problem:`Age: ${30 + 5}`. - Mylenie
==z porównywaniem stringów. Równości przyjrzymy się dokładnie później, ale"1" == 1totrue, a"1" === 1tofalse. Wybieraj===. - Założenie, że
lengthto liczba znaków. Dla emoji i innych znaków z par zastępczych"".lengthto 2, a nie 1. Użyj[..."".length]alboArray.from(s).length, gdy potrzebujesz znaków widzianych przez użytkownika.
Dalej: Number i BigInt
Stringi to jeden typ prymitywny, liczby to drugi, a system liczbowy JavaScript ma własne dziwactwa: jeden typ Number dla liczb całkowitych i zmiennoprzecinkowych oraz BigInt na wypadek, gdy to nie wystarcza. O tym na następnej stronie.
Najczęściej zadawane pytania
Czym różnią się cudzysłowy od backticków w JavaScript?
Apostrofy (') i cudzysłowy (") tworzą zwykłe stringi i można ich używać zamiennie. Backticki (`) tworzą template literals, które obsługują interpolację przez ${...} i obejmują wiele linii bez znaków ucieczki. Sięgaj po backticki zawsze, gdy wstawiasz zmienną albo piszesz tekst w kilku liniach.
Jak wstawić zmienną do stringa w JavaScript?
Użyj template literal: otocz tekst backtickami i umieść wyrażenie w ${...}. Na przykład `Hello, ${name}!` oblicza name i wkleja wynik do tekstu. W środku może stać dowolne wyrażenie: ${a + b}, ${user.name.toUpperCase()}, a nawet zagnieżdżone template literals.
Czy stringi w JavaScript są niemutowalne?
Tak. Każda metoda stringa (toUpperCase, slice, replace i tak dalej) zwraca nowy string, zamiast zmieniać oryginał. Jeśli napiszesz s.toUpperCase() i nigdzie nie przypiszesz wyniku, nic się nie zmieni. To ten sam model co w przypadku stringów w Pythonie czy Javie.
Czym są tagged template literals?
Tagged template literal wywołuje funkcję, przekazując jej osobno kawałki tekstu szablonu i wstawione wartości: tag`Hello, ${name}` wywołuje tag(["Hello, ", ""], name). Biblioteki takie jak styled-components i graphql-tag używają tagów, żeby przetworzyć albo przekształcić szablon przed zwróceniem wyniku.