Kontynuujemy naukę języka JavaScript. Tym razem weźmiemy się za kolejne, jeszcze nam nieznane elementy konstrukcji tego języka, takie jak pętle for i while, switch statement oraz kilka innych podstawowych zagadnień.

Tradycyjnie zaczniemy od utworzenia pliku HTML z templatką, której zawartość tagu <script> będziemy wypełniać.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Welcome to my website</h1>
    
    <script>
        //nasz kod tutaj
    </script>
</body>
</html>

Istnieją też inne metody na wykonywanie kodu JS, które opisałem w pierwszym tutorialu, natomiast to jest nasza metoda proponowana.

Pętla for i while – klasyczna pętle

Pętla for składa się z trzech bloków. Jeden blok tworzy zmienną, drugi stawia warunek kontynuacji pętli, trzeci stanowi instrukcję co zrobić po każdym wykonaniu pętli.

Wewnątrz nawiasów klamrowych wykonujemy pętlę, mając do dyspozycji naszą zmienną.

<script>
        for(let n = 0; n <= 10; n++){
        console.log(n);
        }
    </script>

Mamy tutaj pętlę for, która tworzy zmienną n i przypisuje jej wartość 0. Blok warunkowy nakazuje kontynuowanie pętli tak długo, jak n jest mniejsze lub równe 10. Blok ostatni zwiększa n o 1 po każdym obrocie pętli.

Wewnątrz pętli wyświetlamy n. Efektem tego będzie wyświetlenie w konsoli liczb od 0 do 10.

Pętla while jest podobna, ale jednak inna, ponieważ przyjmuje tylko warunek. Ten sam kod odtworzony w pętli while wygląda tak:

<script>
        let n = 0;
        while(n <= 10){
            console.log(n);
            n++;
        }
    </script>

Tworzymy zmienną n (poza pętlą) i przypisujemy jej wartość. Stawiamy warunek, aby pętla była kontynuowana tak długo, jak n jest mniejsze/równe 10.

Wyświetlamy n i zwiększamy o 1 (n++ to właśnie zwiększenie wartości n o 1).

Też mamy tutaj wypisanie liczb od 0 do 10. Jedyna różnica jest taka, że w pętli for nasze n „ginie”, przestaje istnieć po wykonaniu się pętli. W pętli while n jest stworzone poza pętlą i ta zmienna nadal „żyje” (z wartością 11, czyli pierwszą wartością, która przestała spełniać warunek).

Napisy, tablice – długość i indeks

Znamy już typ napisowy oraz typ liczbowy, najwyższy czas poznać typ, jakim jest tablica, czyli uszeregowany kontener różnych wartości dowolnego typu.

Oto trzy zmienne z trzema różnymi typami danych:

<script>
        let num = 10;
        let msg = "Hello";
        let names = ["John", "Jane", "Bob"];
    </script>

Mamy tutaj liczbę, napis oraz tablicę (zawierającą napisy, ale tablica może zawierać dowolne typy, także mieszankę różnych typów).

Typ liczbowy num możemy poddać znanej nam już inkrementacji:

<script>
        let num = 10;
        let msg = "Hello";
        let names = ["John", "Jane", "Bob"];
        num++;
        console.log(num);
        //11
    </script>

Typy napisowe i tablicowe posiadają natomiast coś takiego jak długość:

<script>
       
        let msg = "Hello";
        let names = ["John", "Jane", "Bob"];
        console.log(msg.length);
        console.log(names.length);
        //5
        //3
    </script>

Ponadto typy napisowe i tablicowe można wyświetlać za pomocą indeksu. Indeksowanie zaczyna się od liczby 0, która jest indeksem pierwszej litery/pierwszego elementu i każdy kolejny element/litera ma indeks o jeden większy.

Wygląda to tak:

 <script>
       
        let msg = "Hello";
        let names = ["John", "Jane", "Bob"];
        console.log(msg[0]); //H
        console.log(msg[1]); //e
        console.log(names[0]); //John
        console.log(names[1]); //Jane
    </script>

Nietrudno się domyślić, że indeks ostatniego elementu to będzie długość tablicy/napisu minus 1, ponieważ indeksujemy od 0.

<script>
       
        let msg = "Hello";
        let names = ["John", "Jane", "Bob"];
        console.log(names[2]); //Bob
        console.log(names[names.length - 1]); //Bob
    </script>

Zadanie 1 – wypisz napis od tyłu

Chcemy napisać funkcję, która wypisze nam jakiś napis, litera po literze, od tyłu. W wersji docelowej – zwróci nam napis odwrócony.

Zobaczmy najpierw, jak zabrać się za wypisanie napisu od tyłu:

<script>
        let msg = "Hello";
        let idx = msg.length - 1;
        while(idx >= 0){
        console.log(msg[idx]);
        idx--;
        }
    </script>

Mamy tutaj napis msg. Chcemy zacząć go wypisywać od ostatniego indeksu, a zatem potrzebna jego długość minus 1. Potrzebny też warunek do pętli, aby działała tak długo, jak idx jest większe lub równe 0 (zero to indeks pierwszej litery).

Wypisujemy msg o indeksie ostatnim i zmniejszamy indeks o 1 (idx–). W ten sposób przechodzimy po całym napisie od tyłu do samego początku.

A jak odwrócić napis?

<script>
        let msg = "Hello";
        let idx = msg.length - 1;
        let msg_reversed = ""
        while(idx >= 0){
        msg_reversed += msg[idx];
        idx--;
        }
        console.log(msg_reversed);
        //olleH
    </script>

Tworzymy pusty napis msg_reversed. Przechodzimy w pętli po napisie zaczynając od indeksu ostatniego i idąc w kierunku zera. Do msg_reversed dopisujemy element o indeksie ostatnim, potem przedostatnim i tak idąc na koniec pętli otrzymujemy napis odwrócony.

Teraz zróbmy z tego funkcję:

<script>
        function reverse_str(str){
            let str_reversed = "";
            let last_idx = str.length - 1;
            while(last_idx >= 0){
            str_reversed += str[last_idx];
            last_idx--;
            }
            return str_reversed;
        }
        console.log(reverse_str("Hello"));
        //olleH
    </script>

Funkcja przyjmuje argument str (nasz napis) i robi dokładnie to samo, co wcześniej robiliśmy, dopisuje do str_reversed litery od ostatniej do pierwszej, zwracając odwrócony napis.

Zadanie 2 – wypisz imiona wielką literą

Mamy taką oto tablicę, zawierającą imiona, które będziemy chcieli wypisać wielką literą:

 <script>
        let names = ["John", "Jane", "Bob"];
    </script>

Aby wypisać imię, wystarczy użyć console.log, nazwy naszej tablicy i odpowiedniego indeksu:

<script>
        let names = ["John", "Jane", "Bob"];
        console.log(names[0]);
        //John
    </script>

Aby zrobić to wielką literą, musimy użyć funkcji toUpperCase na naszym napisie:

<script>
        let names = ["John", "Jane", "Bob"];
        console.log(names[0].toUpperCase());
        //JOHN
        console.log(names[1].toLowerCase());
        //jane
    </script>

Mamy też funkcję toLowerCase, która działa odwrotnie, napis wyświetla małą literą.

Wracajmy do naszego zadania – mamy wypisać każde imię wielką literą. Użyjemy do tego pętli for, która tworzy liczbę o wartości 0 i zwiększa ją tak długo, aż skończą się nam indeksy:

<script>
        let names = ["John", "Jane", "Bob"];
        for(let idx = 0; idx < names.length; idx++){
        console.log(names[idx].toUpperCase());
        }
        //JOHN
        //JANE
        //BOB
    </script>

Pętla for tworzy zmienną idx o wartości 0 (indeks pierwszy). Kontynuuje tak długo, jak indeks jest mniejszy niż długość tablicy (która jest zawsze o 1 dłuższa od ostatniego indeksu).

W pętli wypisujemy imię o podanym indeksie podniesione do wielkiej litery.

Zadanie 3 – sprawdź, czy znak jest literą

Chcemy napisać funkcję, która sprawdza, czy dany znak jest literą czy nie. W wielu językach programowania mamy takie funkcje wbudowane, które sprawdzą, czy podany znak jest literą, czy nie (np. cyfrą, znakiem specjalnym, spacją i tak dalej).

W JS tego nie mamy, ale mamy w zasadzie wszystko, co jest nam potrzebne, wystarczy trochę pogłówkować.

<script>
        let letter = "A";
        let digit = "1";
        let special = "!";
        console.log(letter.toUpperCase()); //A
        console.log(letter.toLowerCase()); //a
        console.log(digit.toUpperCase()); //1
        console.log(digit.toLowerCase()); //1
        console.log(special.toUpperCase()); //!
        console.log(special.toLowerCase()); //!
    </script>

Jak widać funkcje toUpperCase oraz toLowerCase mają wpływ tylko na litery, które zmniejszają/zwiększają o ile już nie są odpowiedniej wielkości.

Na cyfry, znaki specjalne oraz inne spacje te funkcje nie mają żadnego wpływu. Wiemy też, że litera musi być napisem o długości 1, dłuższy napis literą nie będzie.

Teraz możemy napisać naszą funkcję:

<script>
        let letter = "A";
        let digit = "1";
        let special = "!";
        function is_letter(str){
            if(str.length !== 1){
                return false;
            }
            return str.toLowerCase() !== str.toUpperCase();
        }
        console.log(is_letter(letter));
        console.log(is_letter(digit));
        console.log(is_letter(special));
        console.log(is_letter("longer text"));
        //true
        //false
        //false
        //false
    </script>

Nasza funkcja przyjmuje napis jako argument. Napis o długości innej niż 1 zwraca fałsz. Jeżeli długość się zgadza – zwracamy operację logiczną, w której nasz napis zapisany małą literą ma nie być równy napisowi zapisanemu wielką literą (!== oznacza „nie jest równy”).

Wiemy, że „A”.toLowerCase() da nam „a” zaś „A”.toUpperCase() daje „A”. Tymczasem znaki niebędące literami są takie same w tym wypadku i oblewają nasz warunek, że mają się różnić.

Tak działa nasza funkcja.

Switch statement – przełącznik

Jak działa switch najlepiej zobrazuje przykład:

<script>
        let names = ["John", "Jane", "Bob"];
        let name = names[0];

        switch(name) {
        case 'John':
            console.log("John is an admin");
            break;
        case 'Jane':
            console.log("John is our moderator");
            break;
        case 'Bob':
            console.log("I know Bob");
            break;
        default:
            console.log(`I dont know ${name}`);
        }
        //John is an admin
    </script>

Mamy imiona oraz zmienną imię. Teraz przypisaliśmy do niej Johna. Switch bierze zmienną imię i porównuje ją z naszymi blokami „case”.

Mamy blok dla wartości 'John’ z instrukcją co zrobić (na końcu obowiązkowo słówko „break” sygnalizujące koniec bloku case), mamy case 'Jane’, 'Bob’ oraz 'default’, który pokazuje, co zrobić, gdy żadna wartość nie pasuje.

Możemy się trochę tym pobawić:

<script>
        let names = ["John", "Jane", "Bob"];
        let name = names[1];

        switch(name) {
        case 'John':
            console.log("John is an admin");
            break;
        case 'Jane':
        case 'Bob':
            console.log(`${name} is our moderator!`);
            break;
        default:
            console.log(`I dont know ${name}`);
        }
        //Jane is our moderator
    </script>

Teraz do name przypisaliśmy element o indeksie 1, czyli „Jane”. Przypisaliśmy też dwa bloki case (Bob i Jane) dla jednej akcji, która ma nam wypisać imię i informację, że ta osoba jest naszym moderatorem.

Teraz spróbujmy jeszcze, czy blok default nam działa:

<script>
        let names = ["John", "Jane", "Bob"];
        let name = 'Jim';

        switch(name) {
        case 'John':
            console.log("John is an admin");
            break;
        case 'Jane':
        case 'Bob':
            console.log(`${name} is our moderator!`);
            break;
        default:
            console.log(`I dont know ${name}`);
        }
        //I dont know Jim
    </script>

Megazadanie – sprawdź, czy jest samogłoską

Pozbierajmy naszą wiedzę do kupy. Chcemy napisać funkcję, która bierze napis, sprawdza, czy ten napis jest literą, samogłoską „aeiou” bądź też czymś innym i wyświetla stosowną informację.

Na początek funkcja sprawdzająca, czy coś jest literą, już ją sobie wcześniej napisaliśmy:

<script>
        function is_letter(str){
            if(str.length !== 1){
                return false;
            }
            return str.toLowerCase() !== str.toUpperCase();
        }
        console.log(is_letter("A"));
        console.log(is_letter(" "));
        console.log(is_letter("!"));
        console.log(is_letter("Abcd"));
        //true
        //false
        //false
        //false
    </script>

Teraz, mając tę funkcję pomocniczą, przechodzimy do pisania funkcji głównej:

<script>
        function is_letter(str){
            if(str.length !== 1){
                return false;
            }
            return str.toLowerCase() !== str.toUpperCase();
        }
        function check_letter(letter){
            switch(letter){
            case 'a':
            case 'e':
            case 'i':
            case 'o': 
            case 'u':
                console.log(`${letter} is a vowel`);
                break;
            default:
                if(is_letter(letter))
                    console.log(`${letter} is not a vowel`);
                
                else
                    console.log(`text ${letter} is not a letter`);
            }
            
        }

        check_letter('a');
        check_letter('z');
        check_letter('asdasd');
        //a is a vowel
        //z is not a vowel
        //text asdasd is not a letter
    </script>

Mamy tutaj switch, który sprawdza, czy litera to samogłoska i wyświetla nam odpowiednia informację. Mamy też blok default, w którym sprawdzamy, czy mamy w ogóle do czynienia z literą i wyświetlamy stosowną informację.

Co jeszcze możemy poprawić? Po pierwsze, obsługę wielkich liter. Na chwilę obecną „A” nie będzie traktowane jako samogłoska, bo nie pasuje do żadnego case. Możemy to naprawić:

<script>
        function is_letter(str){
            if(str.length !== 1){
                return false;
            }
            return str.toLowerCase() !== str.toUpperCase();
        }
        function check_letter(letter){
            switch(letter.toLowerCase()){
            case 'a':
            case 'e':
            case 'i':
            case 'o': 
            case 'u':
                console.log(`${letter} is a vowel`);
                break;
            default:
                if(is_letter(letter))
                    console.log(`${letter} is not a vowel`);
                
                else
                    console.log(`text ${letter} is not a letter`);
            }
            
        }

        check_letter('a');
        check_letter('A');
        //a is a vowel
        //A is a vowel
    </script>

Teraz nasz switch nie porównuje litery jako takiej, ale literę obniżoną do zapisu małą literą. Dzięki temu „A” przechodzi nasz warunek.

Zrobiliśmy dzisiaj naprawdę dużo. Najwyższa pora na małą przerwę i przeanalizowanie tego, co już poznaliśmy.