PodstawyProgramowanieTypy danych
#JS#javascript#typy#data#types#podstawy#string
Posted on 23.05.2024
W poprzednim wpisie om贸wi艂em pokr贸tce typy danych w JavaScripcie i napomkn膮艂em o j臋zykach typowanych statycznie i dynamicznie. Najwy偶szy czas zatem przyjrze膰 si臋 dok艂adniej poszczeg贸lnym rodzajom danych. Pierwszy na tapet wje偶d偶a string.
Gacie na wacie, czyli stringi w kodzie
Litera艂, ci膮g znak贸w, string - nie wa偶ne, jak to nazwiemy, wa偶ne czym jest.
Na MDN mo偶emy znale藕膰, 偶e The String object is used to represent and manipulate a sequence of characters (Obiekt String s艂u偶y do reprezentowania ci膮gu znak贸w i manipulowania nim). Innymi s艂owy mo偶emy pod zmienn膮 typu string umie艣ci膰 dowolny ci膮g znak贸w, zar贸wno pojedynczy symbol, jak i ca艂ego Pana Tadeusza.
Celowo napisa艂em o pojedynczym symbolu, bo string przyjmuje nie tylko litery, ale dowolne znaki: ma艂e i wielkie litery, cyfry, znaki specjalne.
const stringWithLetters = 'Ala ma kota';
const stringWithNumber = 'Ala ma 2 koty';
const stringWithNumberAndSpecial = 'Czy Ala ma 2 koty?!';
Sk膮d interpreter wie?
Najwa偶niejsze pytanie, to w jaki spos贸b zadeklarowa膰 warto艣膰 typu string, 偶eby interpreter j膮 poprawnie odczyta.
S膮 na to trzy sposoby. String mo偶na zadeklarowa膰 u偶ywaj膮c cudzys艂ow贸w, apostrof贸w lub tzw. backtick贸w (`).
const singleQuoteString = 'Ala ma kota.';
const doubleQuoteString = "Ala ma kota.";
const backtickString = `Ala ma kota.`;
Warto pami臋ta膰, 偶e og贸lnie przyj臋t膮 praktyk膮 jest wyb贸r pomi臋dzy cudzys艂owem a apostrofem i trzymanie si臋 tej notacji w ca艂ym projekcie. U偶ycie backtick贸w - cho膰 w przypadku powy偶szego przyk艂adu da identyczny efekt, jak cudzys艂owy i apostrofy - wymaga nieco dok艂adniejszego om贸wienia, do czego przejd臋 za chwil臋.
Stringi w praktyce
Ze zmiennymi typu string zetkniecie si臋 praktycznie na ka偶dym kroku, nie wa偶ne w jakim j臋zyku b臋dziecie programowa膰. Wszelkie linki, adresy, imiona - to wszystko jest przechowywane jako string. Ca艂y wpis, kt贸ry w艂a艣nie czytacie, jego tytu艂 czy nazwa kategorii te偶 s膮 zapisany jako string.
Ale czy ze stringiem mo偶na zrobi膰 co艣 wi臋cej, ni偶 tylko go wy艣wietli膰? Oczywi艣cie! Poni偶ej znajdziecie najcz臋艣ciej u偶ywane operacje na stringach (tak, wiem, jak to brzmi 馃槀).
Konkatenacja, czyli 艂膮czenie string贸w
Jedn膮 z podstawowych (i najprostszych) operacji, jakie mo偶emy przeprowadzi膰 na ci膮gach znak贸w, jest ich 艂膮czenie. W klasycznej formie stringi 艂膮czymy znakiem +:
const name = 'Jan';
const lastName = 'Kowalski'
const fullName = name + ' ' + lastName;
//'Jan Kowalski'
Jak zapewne zauwa偶yli艣cie, pomi臋dzy 艂膮czonymi stringami doda艂em jeszcze jeden, zawieraj膮cy tylko spacj臋 (i nie - nie jest to to samo, co pusty ci膮g!). Bez tego otrzymaliby艣my wynik JanKowalski.
const fullName = name + lastName;
//'JanKowalski'
const emptyString = '';
W powy偶szym przyk艂adzie zamie艣ci艂em te偶 dla dociekliwych przyk艂ad pustego ci膮gu. Warto zauwa偶y膰 r贸偶nic臋 mi臋dzy ci膮giem ze spacj膮 (' ') a pustym stringiem ('').
Czy stringi mo偶na 艂膮czy膰 inaczej? Tak - i do tego mo偶emy wykorzysta膰 wspomniane ju偶 backticki:
const fullName = `${name} ${lastName}`
//'Jan Kowalski'
Stringi mo偶na tak偶e 艂膮czy膰 z danymi innych typ贸w. Najcz臋艣ciej jest to u偶ywane do 艂膮czenia ci膮gu znak贸w z liczb膮.
const age = 30;
console.log(typeof age);
//number
const personInfo = name + ' ' + lastName + ' is ' + age + ' years old';
//'Jan Kowalski is 30 years old'
const backtickPersonInfo = `${name} ${lastName} is ${age} years old`;
//'Jan Kowalski is 30 years old'
Zanim przejd臋 do dalszych przyk艂ad贸w wyja艣nijmy, w jaki spos贸b interpreter JS 艂膮czy dane r贸偶nych typ贸w.
JavaScript pod mask膮 stara si臋 dopasowa膰 do siebie typy 艂膮czonych danych. M贸wimy o tzw. niejawnej konwersji typ贸w. W wyniku konkatenacji stringa i liczby otrzymujemy nowy string:
const number = 11
const string = '2'
const add = number + string;
//'112'
console.log(typeof add)
//'string'
St膮d bior膮 si臋 cz臋ste b艂臋dy. Je艣li przeoczymy, 偶e nasza liczba zosta艂a w kt贸rym艣 momencie przedstawiona jako string (np. przes艂ana z formularza), to wyniki mog膮 nas mocno zaskoczy膰. Nas - albo u偶ytkownika, je艣li nie wy艂apiemy b艂臋du na czas. Pos艂uguj膮c si臋 powy偶szym przyk艂adem - je艣li pisz膮c kod zak艂adali艣my, 偶e zmienna string te偶 by艂aby typu number, to otrzymane 112 do艣膰 znacz膮co odbiega艂oby od zak艂adanego 13, je艣li mieliby艣my do czynienia z dwoma liczbami.
Innymi typami, do kt贸rych JS mo偶e wykona膰 niejawn膮 konwersj臋 s膮 number oraz boolean.
Por贸wnywanie string贸w
Nie ma co ukrywa膰, stringi por贸wnuje si臋 bardzo cz臋sto. O samym por贸wnywaniu r贸偶nych warto艣ci powiem wi臋cej podczas omawiania typu boolean, ale o pewnych podstawach trzeba wspomnie膰 ju偶 teraz.
W JavaScript istnieje osiem logicznych operator贸w. S膮 to:
- == (r贸wne),
- === (r贸wne ze sprawdzeniem typu),
- != (r贸偶ne),
- !== (r贸偶ne ze sprawdzeniem typu),
- > (wi臋ksze),
- >= (wi臋ksze lub r贸wne),
- < (mniejsze),
- <= (mniejsze lub r贸wne).
Najrzadziej wykorzystuje si臋 por贸wnania wykonywane bez sprawdzania typ贸w (== oraz !=), ale o tym kiedy indziej.
Podczas por贸wnywania string贸w nale偶y pami臋ta膰 o kilku kwestiach. Przede wszystkim stringi s膮 case sensitive, czyli wielko艣膰 ma znaczenie - liter oczywi艣cie 馃槈.
Po drugie w przypadku por贸wnywania, kt贸ry string jest mniejszy/wi臋kszy pod uwag臋 brana jest bezwzgl臋dnie kolejno艣膰 alfabetyczna. Niby oczywiste, ale kiedy mamy w stringu liczb臋, to ju偶 mo偶e by膰 ciekawie.
Pusty string jest tzw. warto艣ci膮 falsy, czyli jest zawsze fa艂szywy logicznie.
'Ala' === 'ala'; //false
'11' > '2' //false
!!'' //false
Typ jest obiektem!!!
Chcia艂bym jeszcze raz wr贸ci膰 do definicji typu string (MDN):
The String object is used to represent and manipulate a sequence of characters.
S艂owo object znalaz艂o si臋 tutaj nieprzypadkowo. JavaScript wszystkie typy traktuje jak obiekty. Obiekty, kt贸re maj膮 swoje metody i w艂a艣ciwo艣ci. Polecam zajrze膰 na linkowan膮 ju偶 kilkukrotnie stron臋 MDN po艣wi臋con膮 stringom. Tam, w menu po lewej stronie znajdziecie wszystkie metody, jakie posiada obiekt string. Poni偶ej za艣 znajdziecie te najpopularniejsze.
D艂ugo艣膰 stringa
Ka偶dy ci膮g znak贸w posiada jak膮艣 d艂ugo艣膰. Jest to nic innego, jak ilo艣膰 znak贸w (w艂膮cznie ze spacjami itp.), jakie na dany ci膮g si臋 sk艂adaj膮. Warto艣膰 t臋 mo偶emy sprawdzi膰 poprzez metod臋 length
const string = 'Ala';
const longerString = '呕yrafa';
const spaceString = ' ';
const emptyString = '';
console.log(string.length)
//3
console.log(longerString.length)
//6
console.log(spaceString.length)
//1
console.log(emptyString.length)
//0
Przeszukiwanie string贸w
Poza wiedz膮, jak膮 string ma d艂ugo艣膰 mo偶emy tak偶e sprawdzi膰, jaki znak znajduje si臋 w konkretnym miejscu naszego ci膮gu. S膮 na to dwie metody: charAt() lub bezpo艣rednie odwo艂anie si臋 do poszukiwanego indeksu (dok艂adnie w taki sam spos贸b, jak w tablicach).
const string = 'Ala';
console.log(string.charAt(1));
//'l'
console.log(string.charAt(3))
//''
console.log(string[1]]);
//'l'
console.log(string[3])
//undefined
Nale偶y bezwzgl臋dnie pami臋ta膰, 偶e indeksowanie zaczyna si臋 od warto艣ci 0! To znaczy, 偶e pierwszy znak ci膮gu b臋dzie mia艂 indeks r贸wny 0, za艣 ostatni length - 1
W przypadku metody charAt() - je艣li b臋dziemy chcieli sprawdzi膰 znak o nieistniej膮cym indeksie, to otrzymamy pusty string. Nieco inaczej wygl膮da to przy bezpo艣rednim odwo艂aniu do indeksu. W takiej sytuacji, je艣li poszukiwany indeks nie b臋dzie istnia艂, to dostaniemy warto艣膰 undefined.
Ciekaw膮 metod膮 na przeszukiwanie string贸w jest te偶 metod at(). Dzia艂a ona bardzo podobnie do charAt() - z tym, 偶e pozwala tak偶e na przeszukiwanie ci膮gu od ko艅ca. Mo偶na to zrobi膰 pos艂uguj膮c si臋 ujemnym indeksem.
Trzeba pami臋ta膰, 偶e w przypadku wyszukania nieistniej膮cego indeksu otrzymamy warto艣膰 undefined, podobnie jak to by艂o przy bezpo艣rednim odniesieniu do indeksu!
const string = 'Ala ma kota.';
console.log(string.at(0));
//'A'
console.log(string.at(-2));
//'a'
console.log(string.at(12));
//undefined
console.log(string.charAt(-2));
//''
Wyszukiwanie fragmentu stringu
Czasami chcemy sprawdzi膰, czy dany string zawiera w sobie jak膮艣 fraz臋. Mo偶e to by膰 wyszukiwarka na stronie lub te偶 jaki艣 element walidacji - zastosowa艅 jest bardzo du偶o. JavaScript daje nam metod臋 includes(), kt贸ra pozwala nam bardzo 艂atwo przeszukiwa膰 stringi.
const string = 'Jedzie poci膮g z daleka.';
const search = 'poci膮g';
string.includes(search) //true
Warto pami臋ta膰 o zasadach por贸wnywania string贸w w JavaScripcie. Jak wspomina艂em - wielko艣膰 liter ma znaczenie! Oczywi艣cie jest spos贸b, 偶eby to obej艣膰, ale o tym za chwil臋.
Por贸wnywanie z regexami
O samych wyra偶eniach regularnych - czyli regexach - powiem prawdopodobnie wi臋cej w osobnym wpisie. Na ten moment musicie tylko wiedzie膰, czym s膮 wyra偶enia regularne i jak mo偶emy je wykorzysta膰 w pracy ze stringami.
Czym - w ogromnym skr贸cie - s膮 wyra偶enia regularne? To pewien wz贸r, kt贸ry opisuje tekst do por贸wnania. Warto wspomnie膰, 偶e regex nie jest bibliotek膮 czy konkretnym j臋zykiem programowania.
Metoda match() pozwala w艂a艣nie na por贸wnanie stringa do wyra偶enia regularnego.
const regex = /[A-Z]/g;
const string = 'Ala ma kota';
const found = string.match(regex);
//['A']
W powy偶szym przyk艂adzie sprawdzamy, czy w ci膮gu znak贸w wyst臋puj膮 dowolne wielkie litery. Wynikiem metody match() jest tablica zawieraj膮ca pasuj膮ce do wyra偶enia znaki. Je艣li 偶aden symbol ze stringa nie pasuje do wyra偶enia regularnego, to wynikiem b臋dzie pusta tablica.
Przyk艂adowo, je艣li chcemy sprawdzi膰, czy podany string jest adresem email, mo偶emy u偶y膰 poni偶szego wzoru:
const emailRegex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/g;
const email = 'test@e.mail';
const incorrectEmail = 'test.e.mail';
const isEmail = (string) => {
return !!string.match(emailRegex)
};
isEmail(email); //true
isEmail(incorrectEmail); //false
Ci臋cie string贸w
Czasami mo偶e si臋 zdarzy膰 tak, 偶e potrzebny nam jest tylko fragment stringa. Pomocna w tym jest metoda slice(), kt贸ra jako argument przyjmuje index i zwraca nowy string. Indeksem jest numer znaku (liczony od 0), od kt贸rego chcemy zachowa膰 zawarto艣膰 stringa.
const string 'Ala ma kota';
const short = string.slice(4);
//'ma kota'
Je艣li jako parametr podamy dwa indeksy, w贸wczas wynikiem b臋dzie ci膮g, kt贸ry znajduje si臋 mi臋dzy nimi:
const string 'Ala ma kota';
const short = string.slice(4, 6);
//'ma'
Za pomoc膮 metody slice() mo偶na "wycina膰" tak偶e fragmenty stringa od jego ko艅ca - w贸wczas u偶yjemy ujemnych indeks贸w.
const string 'Ala ma kota';
const short = string.slice(-5); //'kota.'
const shortRange = string.slice(-5, -1); //'kota'
Zamiana stringa w tablic臋
Niekiedy jest tak, 偶e chcemy zawarto艣膰 stringa umie艣ci膰 w tablicy, np. jako osobne s艂owa. S艂u偶y do tego metoda split(). Jako argument przyjmuje ci膮g, kt贸ry b臋dzie u偶yty jako separator. Wynikiem jest - co do艣膰 oczywiste - tablica.
const string 'Ala ma kota';
const short = string.split(' ');
//['Ala', 'ma', 'kota.']
Powy偶ej jako separatora u偶yli艣my spacji (' '), przez co w tablicy mo偶emy znale藕膰 pojedyncze wyrazy z ci膮gu. Je艣li chcieliby艣my utworzy膰 tablic臋 z pojedynczych znak贸w, to jako argument musieliby艣my poda膰 pusty ci膮g (''):
const string 'Ala ma kota';
const short = string.split('');
//["A", "l", "a", " ", "m", "a", " ", "k", "o", "t", "a", "."]
Warto zauwa偶y膰, 偶e w tym przypadku w tablicy znajdziemy tak偶e spacje, znaki specjalne, interpunkcyjne itp. Istniej膮 oczywi艣cie sposoby, 偶eby si臋 ich pozby膰 z finalnej tablicy - ale p贸ki co zostawmy to, jak jest.
Zmiana wielko艣ci znak贸w
Mo偶e si臋 zdarzy膰, 偶e b臋dziemy chcieli, 偶eby zmieni膰 wielko艣膰 litery w naszym ci膮gu znak贸w. Czasami s膮 to wzgl臋dy estetyczne, np. aby zapisa膰 jaki艣 tytu艂 kapitalikami. Innym razem b臋dziemy chcieli por贸wna膰 ze sob膮 dwa ci膮gi znak贸w, upewniaj膮c si臋, 偶e wielko艣膰 znak贸w nie wp艂ynie na wynik (a jak by艂o wspomniane - wielko艣膰 znak贸w jest przy por贸wnaniach istotna). W贸wczas mo偶emy skorzysta膰 z metod toLowerCase() lub toUpperCase(). Wynikiem b臋dzie nowy string.
const string = 'Ala ma kota.';
string.toLowerCase(); //'ala ma kota.'
string.toUpperCase(); //'ALA MA KOTA.'
const test = 'Marek';
'marek' === string; //false
'marek'.toLowerCase === test.toLowerCase; //true
'marek'.toUpperCase === test.toUpperCase; //true
To wszystko?
Oczywi艣cie, 偶e nie. Obiekt string posiada jeszcze kilka innych, rzadziej u偶ywanych metod. Wszystkie znajdziecie na wspominanej ju偶 stronie MDN. Gor膮co zach臋cam do ich przejrzenia i potestowania.
Template literals
Pami臋tacie, jak wspomina艂em wcze艣niej, 偶e jeszcze wr贸cimy do deklarowania string贸w za pomoc膮 backtick贸w? No to w艂a艣nie wracamy 馃槈
By膰 mo偶e spotkali艣cie si臋 kiedy艣 z terminem ES lub ECMAScript. W ten spos贸b oznacza si臋 oficjalne wersje j臋zyka JavaScript. Numer, jaki wyst臋puje po tym ES oznacza wersj臋 lub rok, w kt贸rym wersja zosta艂a wypuszczona. Na przyk艂ad mamy ES6, co jest dok艂adnie t膮 sam膮 wersj膮, co ES2015.
Czemu o tym wspominam? Poniewa偶 wersja ES6 by艂a prawdziw膮 rewolucj膮 dla JavaScriptu. Jedn膮 z nowo艣ci, jakie przynios艂a by艂y w艂a艣nie template literals, lub - jak kto woli - template string. I jest to w艂a艣nie zapis string贸w za pomoc膮 backtick贸w.
Ok, a co w tym takiego niezwyk艂ego? Ot, nowa forma zapisu. Noooo... nie do ko艅ca. Template literals bardzo rozbudowuj膮 mo偶liwo艣ci pracy ze stringami. Jak cho膰by ju偶 wspomniane u偶ycie zmiennych wewn膮trz stringa (co nazywamy interpolacj膮 string贸w).
const number = 2;
const string = `Ala ma ${number} koty.`
// 'Ala ma 2 koty.'
Ale to nie wszystkie mo偶liwo艣ci, jakie daje u偶ycie template literals. Pozwalaj膮 one tak偶e na utworzenie string贸w wielowierszowych bez konieczno艣ci posi艂kowania si臋 znakiem nowej linii (\n):
const oldNotation = 'Ala ma: \n- 2koty, \n- psa, \n- chomika.';
/*
Ala ma:
- 2 koty,
- psa,
- chomika.
*/
const template = `Ala ma:
- 2 koty,
- psa,
- chomika.`
/*
Ala ma:
- 2 koty,
- psa,
- chomika.
*/
Ponadto template literals pozwalaj膮 na u偶ycie wyra偶e艅 javascriptowych wewn膮trz string贸w.
const isLoggedIn = true;
const userName = 'Marek';
const greeting = `Witaj, ${isLoggedIn ? username : 'Go艣ciu'}!`;
// 'Witaj, Marek!
Template literals oferuj膮 tak偶e kilka innych mo偶liwo艣ci, o kt贸rych mo偶na przeczyta膰 na stronie MDN.
Co dalej?
Ok, poznali艣my najwa偶niejsze informacje na temat danych typu string, najwa偶niejsze operacje, jakie mo偶emy na nich przeprowadza膰 oraz najcz臋艣ciej stosowane metody.
My艣l臋, 偶e w nast臋pnej cz臋艣ci tej serii na tapet we藕miemy dane typu number. A tymczasem zapraszam na mojego twixera 馃槉
Do nast臋pnego!