Moduł1 - Zajęcia 1 - Zmienne i typy

Section1: Poznawanie JavaScript

Kiedy myślimy o programowaniu, pierwszym skojarzeniem może być lista instrukcji w pliku tekstowym, które ma wykonać komputer.

Kod źródłowy (source code) - pliki zawierające "treść" programu komputerowego zapisaną przy pomocy określonego języka programowania. Opisują one operacje, jakie powinien wykonać komputer na przechowywanych w pamięci lub przesyłanych do niego danych.

Kod źródłowy nie jest zrozumiały w swojej bezpośredniej postaci dla komputera, dlatego istnieje dodatkowy krok, który konwertuje kod źródłowy w pliku w zestaw instrukcji zrozumiałych dla podzespołów (między innymi procesora). Za ten krok odpowiada osobny program - kompilator lub interpreter. Można powiedzieć, że kod piszemy nie dla komputera tylko dla programisty. Kod źródłowy musi być zrozumiały i oczywiście odpowiadać naszym wymaganiom co do jego działania.

Section2: Logiczne myślenie

Na świecie istnieje wiele języków programowania. Kiedy opanujemy jeden z nich, to nauczenie się kolejnych nie jest tak skomplikowane, jak uczenie się języków używanych przez nas na co dzień. Związane jest to z tym, że liczba konstrukcji semantycznych, jest znaczniej mniejsza i na dodatek wiele konceptów po prostu powtarza się niezależnie od tego z którego języka korzystamy (czasem z nieco zmienioną składnią)

Doświadczeni programiści analizują problemy pod kątem algorytmów - zestawu kroków, które należy wykonać, aby osiągnąć określony cel. Algorytm możemy porównać do naszych codziennych działań takich jak przygotowanie herbaty - czynność ta składa się z kolejnych etapów, które pozwalają osiągnąć określony cel. Kiedy zaczniesz odpowiednio analizować problem do rozwiązania, myśląc o nim algorytmicznie i rozbijając go na poszczególne kroki, język programowania stanie się po prostu narzędziem do użycia.

Section3: JavaScript

JavaScript - implementacja specyfikacji EcmaScript, język programowania "wysokiego poziomu", obsługiwany przez każdą współczesną przeglądarkę. Początkowo on został zaprojektowany do zarządzania elementami stron internetowych i obsługiwania interakcji z użytkownikiem (m.in. nasłuchiwania jego akcji takich jak kliknięcia, wpisywanie wartości z klawiatury itp).

JavaScript nie ma żadnego połączenia z językiem Java. To są dwa osobne języki programowania, wykorzystywane w odmiennych kontekstach. Z uwagi na podobną nazwę wśród osób nie związanych z programowaniem bywają ze sobą mylone.

Przy pisaniu Front-endu, JavaScript wykorzystuje się w połączeniu z HTML i CSS dla zapewnienia funkcjonalności strony internetowej, takich jak:

  • proste obliczenia
  • weryfikacja i manipulacja danymi wprowadzonymi przez użytkownika
  • przechowywanie danych w przeglądarce użytkownika (local storage)
  • dynamiczne zmiany w dokumencie HTML
  • reakcja na działania użytkownika: kliknięcia, scrollowanie strony itp
  • tworzenie elementów interaktywnych: galerii, wykresów itp.
  • interakcja z backendem, wysyłanie zapytań, operowanie na danych otrzymanych z serwera

JavaScript połączony z HTML wykonywany jest w przeglądarce. Programista nie posiada narzędzi ani dostępu do plików lub systemu operacyjnego ze względów bezpieczeństwa.

Na dzień dzisiejszy wykorzystując JavaScript można tworzyć:

  • aplikacje webowe, wykorzystując frameworki takie jak React, Vue, Angular i inne
  • backendowe aplikacje na Node.js
  • mobilne aplikacje używając React Native ,Ionic lub Cordova
  • aplikacje desktopowe za pomocą Electron
  • oprogramowanie mikrokontrolerów za pomocą Johnny-Five i Espruino

Niezależnie od tego do czego chcesz używać JavaScript, musisz dobrze znać składnię języka, jego cechy i mechanizmy, trenować myślenie algorytmiczne i rozwiązywać jak najwięcej praktycznych zadań.

Section4: Podłaczenie skryptu

Aby użyć skryptu na swojej stronie, musimy w pliku HTML wykorzystać tag script, gdzie w atrybucie src należy wskazać ścieżkę do zewnętrznego pliku JavaScript.

Aby podłączyć JavaScript z zewnętrznego pliku:

  • Stwórz plik z rozszerzeniem .js i umieść go w folderze js.
  • Później należy wskazać ścieżkę do pliku JS w atrybucie src tagu script.

Nie ma konieczności dodawania plików JavaScript do folderu js, ale jest to przydatna praktyka.

Jeśli skrypt jest podłączony w "head", strona nie będzie się ładować aż do momentu, gdy skrypt w całości zostanie załadowany. Przeglądarka ładuje i wyświetla HTML krok po kroku, budując drzewo elementów HTML. Jeśli zobaczy tag "script", który nie posiada innych atrybutów, to w pierwszej kolejności wykonuje się skrypt, a dopiero później ładuje się reszta dokumentu - bardzo często powoduje to problem, ponieważ skrypt nie będzie miał wtedy dostępu do elementów strony (ponieważ nie są jeszcze załadowane). Dlatego skrypt często podłącza się przed zamykającym tagiem "body", po całej treści, jak w przykładzie.

Alternatywnie możemy dodać do tagu "script" dodatkowy atrybut defer który zaczeka na załadowanie drzewa elementów, wtedy nasz skrypt możemy podłączyć w "head" jak w poniższym przykładzie

Section5: Kilka skryptów

Kiedy podłączamy kilka plików JavaScript do strony, interpretator "odczyta" je w takiej kolejności w jakiej są umieszczone w pliku HTML, co czasem może wywołać błędy spowodowane brakiem zmiennych, jeżeli kolejność jest nieprawidłowa.

Section6: Dev tools

Podczas pisania kodu często spotykamy się z błędami, co jest normalne na każdym poziomie zaawansowania. Konsola przeglądarki pokazuje nam informację dotyczącą strony, w tym wiadomości o błędach, między innymi o tych, które pojawiły się podczas wykonywania się skryptu JS.

Następujące skróty klawiszowe otwierają narzędzia developerskie, gdzie błędy odnajdziemy w zakładce Console:

  • Windows / Linux - Ctrl + Shift + J lub F12
  • MacOS - Command + Option + J

Section7: Podstawy składni

Żeby pisać swój kod, musimy najpierw zapoznać się z terminologią i koncepcjami kodu źródłowego. W tej sekcji mniej ważne będą szczegóły jak działa dany zapis. Ważne jest, aby zapoznać się z podstawową terminologią i składnią (syntax).

Instrukcja

Instrukcja (statement) - jest to powiązany ze sobą zestaw słów kluczowych i symboli ze składni języka, które łączą się, aby wyrazić jedną ideę, instrukcję dla komputera.

a = b * 2;

Instrukcje w JavaScript kończą się średnikiem, który można porównać z kropką na koniec zdania w ojczystym języku. Czasami instrukcja będzie zajmować więcej niż jedną linijkę, więc średniki nie zawsze będą kończyły każdą linię tekstu.

  • a i b - zmienne (jak w równaniu algebraicznym znanym ze szkoły), jest to narzędzie do przechowywania danych, które wykorzystuje program. Zmienna składa się z identyfikatora (nazwy) i wartości przechowywanej w danej zmiennej
  • 2 - wartość liczbowa. Jest to dosłowna wartość (literal value), ponieważ nie jest zapisana w zmiennej
  • = i * - operatory, wykonują działania zmieniające zmienne.

Wyobraźmy sobie, że zmienna b już przechowuje liczbę 10. Wtedy ta instrukcja zostanie zinterpretowana jako

  1. Znajdź zmienną z identyfikatorem b i dowiedz się jaką ma wartość.
  2. Podstaw wartość zmiennej b (10), w miejsce b
  3. Wykonaj operację mnożenia 10 na 2.
  4. Zapisz rezultat wyrażenia po prawej części jako wartość zmiennej a.

Zakończenie instrukcji średnikiem nie zawsze jest konieczne, ale rekomendujemy na początku zawsze go używać. Dzięki temu lepiej zrozumiemy kod i unikniemy ciężkich do odnalezienia błędów.

Section9: Wyrażenie

Instrukcje składają się z elementów składni danego języka, których zbiór nazywamy wyrażeniem, podobnie jak zdanie w języku mówionym składa się z wyrazów.

Wyrażenia (expression) - wartość lub instrukcje które zostają zinterpretowane i sprowadzają się do wartości

[ [a] = [ [b] * [2] ] ]

Instrukcja z przykładu powyżej zawiera 5 wyrażeń, które są oddzielone kwadratowym nawiasem dla wizualizacji (powyższa instrukcja nie jest poprawną składnią języka):

  • [2] - dosłowna wartość.
  • [b]i[a] - zmienne, oznaczające potrzebę podstawienia wartości zmiennej, ale dopiero wtedy, gdy zmienna znajduje się po prawej stronie wyrażenia.
  • [b * 2] - arytmetyczne wyrażenie mnożenia.
  • [a = b * 2] - wyrażenie przypisania. W naszym przypadku wskazuje potrzebę ewaluacji (obliczenia) prawej strony wyrażenia i przypisania wyniku do zmiennej a po lewej stronie wyrażenia.

Istnieją też wyrażenia wywoływania funkcji, porównania wartości itp. Nie będziemy teraz rozważać wszystkich z nich. Istotne na ten moment jest, abyśmy zrozumieli, z jakich części składa się kod źródłowy i jak poprawnie go odczytać. Pozostałe elementy i inne wyrażenia poznamy w kolejnych modułach.

Section10: Interfejs

Kiedy prowadzimy samochód, korzystamy z jego systemów które pozwalają na zmianę jego zachowania (kierownica, pedały, przyciski i przełączniki) W programowaniu zbiór takich "narzędzi" nazywamy interfejsem.

Interfejs - zbiór właściwości i metod dostępnych do użycia w kodzie źródłowym.

Właściwość

Każdy z nas ma właściwości: wzrost, wagę, kolor oczu, czyli opisowe cechy. Dane w kodzie źródłowym również mają właściwości, na przykład, wiersz tekstu ma właściwość - jego długość. Składnia odwoływania się do właściwości jest bardzo prosta - używamy kropki i podajemy nazwę właściwości (zdefiniowaną w standardzie JavaScriptu i do której wartość zostaje przypisana automatycznie bez naszej ingerencji).

essence.nazwa_właściwości

Dla przykładu przejdźmy do właściwości dla wiersza, length, która zawiera liczbę znaków w danym wierszu

"JavaScript is awesome".length;

W tym miejscu, wartością tej właściwości będzie liczba 21

Metoda

Idąc za poprzednią metaforą, metoda to wywołanie akcji, na przykład usiądź lub płyń, czyli aktywne działanie. Podobnie, dane mają własne predefiniowane metody, na przykład możesz dodawać lub usuwać elementy z tablicy, przekształcać ciąg znaków z małych na duże litery itp. Składnia wywoływania metody jest bardzo podobna do wywoływania właściwości, ale na końcu dodawane są nawiasy w których czasem możemy podać dalsze modyfikatory (o tym więcej w innym modułach).

essence.nazwa_metody()

Dla przykładu zwróćmy się do metody wiersza toUpperCase(), który przekształci wszystkie litery na duże.

"JavaScript is awesome".toUpperCase();

Taka instrukcja zostanie ewaluowana do:

"JAVASCRIPT IS AWESOME"

Ta wartość może potem zostać na przykład przypisana do zmiennej i wykorzystana dalej.

Use strict

Nowa instrukcja w specyfikacji ECMAScript 5, która wymusza interpretowanie skryptu w pełnej zgodności z nowoczesnym standardem. Zapobiega to pewnym błędom wynikającym z używania niebezpiecznych i przestarzałych konstrukcji.

Aby ustawić skrypt w trybie ścisłym wystarczy podać dyrektywę na początku pliku JS. Zawsze pisz swój kod w trybie strict (ścisłym).

script.js

"use strict";

Section11: Zmienne i typy prymitywne

Zmienne służą do przechowywania danych i składają się z identyfikatora (nazwy) oraz obszaru w pamięci, w którym przechowywana jest ich wartość. Zmienną możemy sobie wyobrazić jako pudełko z nazwą, w którym przechowywana jest zawartość (wartość zmiennej)

"słowo_kluczowe" "nazwa_zmiennej" = "znaczenie"

Section12: Nazwa zmiennej

  • Pierwszym symbolem musi być litera a-z lub A-Z, symbol podkreślenia _ lub znak dolara $.
  • Kolejne symbole mogą być literami a-z, A-Z, cyframi 0-9, podkreśleniem _ i znakiem dolara $
  • W identyfikatorach rozróżniana jest wielkość liter. To oznacza, że zmienne user, usEr i User nie są tym samym.

Nazwa zmiennej powinna być możliwe zwięzła ale przede wszystkim zrozumiała również dla człowieka czytającego kod.

Standardowo w JavaScript używamy camelCase, przyjęło się również, że zmienne nazywamy po angielsku.

W notacji camelCase pierwsze słowo jest pisane małymi literami, a każda kolejne zaczyna się od dużej np. user, greetUser, getUserData, isActive, activeGuestCount, totalWorkerSalary./p>

Istnieje lista zarezerwowanych słów kluczowych, które mają specjalne znaczenie i są używane jako część składni języka. Nie można użyć słów kluczowych jako identyfikatorów (nazw zmiennych) ponieważ interpreter nie będzie rozumiał naszego zapisu i pojawi się błąd.

Section13: Deklaracja zmiennej

Deklaracja zmiennej najczęściej zaczyna się od słowa kluczowego const. Taka zmienna musi mieć nadaną wartość, po przypisaniu której nie może już być nadpisana.

            // Zmienne const obowiązkowo powinny mieć nadaną
            // wartość podczas deklaracji, w innym przypadku pojawi się błąd.
            const yearOfBirth = 2006;
            console.log(yearOfBirth); // 2006
            
            // Jeśli zadeklarowaliśmy zmienną const, nie możemy już zmienić jej wartości,
            // Przy próbie nadania nowej wartości pojawi się błąd przy wykonaniu skryptu.
            yearOfBirth = 2020; // ❌ Nieprawidłowo, pojawi się błąd
          

W celu zadeklarowania zmiennej, której w przyszłości będzie można przypisać nową wartość, używane jest słowo kluczowe let.

            // Zmienne zadeklarowane za pomocą let 
            // nie muszą mieć wartości w momencie deklaracji.
            let age;

            // Jeśli zadeklarowanej zmiennej za pomocą let nie była przypisana wartość,
            // automatycznie nadana zostanie wartość undefined (nie zdefiniowano).
            console.log(age); // undefined

            // console.log() to metoda do wyświetlenia danych w konsoli przeglądarki,
            // zapoznamy się z nią nieco później.

            // Jeśli zmienna jest zadeklarowana za pomocą let, 
            // możemy nadpisać wartość tej zmiennej.
            age = 14;
            console.log(age); // 14
          

Deklaracja zmiennej bez słowa kluczowego let lub const doprowadzi do błędu, jeśli skrypt jest wykonywany w "strict mode".

Section14: Kiedy wykorzystywać const i let

Jedyną różnicą między const i let jest to, że const nie pozwala na ponowne przypisywanie wartości do zmiennej. Deklaracja const sprawia, że kod jest bardziej czytelny, ponieważ zmienna zawsze odnosi się do tej samej wartości. W przypadku let takiej pewności już nie ma.

let i const należy wykorzystywać w ten sposób:

  • Używaj const domyślnie, większość zmiennych będzie deklarowana właśnie w taki sposób.
  • Używaj let, jeśli będziesz przypisywał nowe wartości do zmiennej podczas wykonywania skryptu.

Section15: constants i CONSTANTS (stałe)

Nazwy CONSTANTS - są zmienne, których znaczenie nie zmienia się nigdy podczas wykonywania całego skryptu i mają znaczenie konfiguracyjne. Nazwy takich zmiennych przyjęło się zapisywać następująco: UPPER_SNAKE_CASE.

            // Zmienna stała, która zawiera wartość koloru
            const COLOR_TEAL = "#009688";

            // Zmienna stała, która zawiera wiadomość powitalną po zalogowaniu się
            const LOGIN_SUCCESS_MESSAGE = "Witamy!";
          

Zdecydowana większość zmiennych to stałe w nieco innym sensie, po prostu nie zmieniają swojej wartości po przypisaniu, ale np. przy kolejnych uruchomieniach skryptu ta wartość może być inna. Nazwy takich zmiennych są zapisywane normalnie w formacie camelCase.

Section16: Odwoływanie się do zmiennej

Ważne jest, aby rozróżnić zmienne niezdefiniowane i niezadeklarowane.

Niezdefiniowane (undefined) - jest to zmienna która została zadeklarowana za pomocą słowa kluczowego let, ale nie posiadająca jeszcze wartości. Domyślnie przypisana wartość początkowa to undefined.

            let username;
            console.log(username);// undefined
          

Niezadeklarowana (undeclared lub not defined) - to zmienna, o nazwie która nie została nigdzie wcześniej zadeklarowana. Próba uzyskania dostępu do zmiennej przed deklaracją spowoduje błąd- na przykład, próba odczytu lub zmiany jej wartości.

            // ❌ Nieprawidłowo, pojawi się błąd
            age = 15; // ReferenceError: Cannot access 'age' before initialization
            console.log(age);// ReferenceError: age is not defined

            // Deklaracja zmiennej age
            let age = 20;

            // ✅ Prawidłowo, odwołujemy się do zmiennej po jej deklaracji
            age = 25;
            console.log(age);// 25
          

Section17: Typy prymitywne

W JavaScript sama zmienna nie jest powiązana z żadnym typem danych, dopiero jej wartość będzie danego typu. Oznacza to, że zmienna może przechowywać wartości różnych typów i możemy przypisywać do tej samej zmiennej wartości różnego typu w obrębie działania naszego skryptu (nie jest to zazwyczaj dobra praktyka, ale jest to możliwe).

Number - liczby całkowite i liczby zmiennoprzecinkowe (z wartościami dziesiętnymi po "kropce")

            const age = 20;
            const points = 15.8;
          

String - wiersz czy też sekwencja znaków. Wiersz rozpoczyna się i kończy się pojedynczym ', lub podwójnym cudzysłowem ".

            const username = "Mango";
            const description = "JavaSript dla początkujących";
          

Boolean - logiczny typ danych. Posiada tylko dwa znaczenia: true lub false. Na przykład na pytanie, czy w pokoju jest włączone światło możemy odpowiedzieć tak (true) lub nie (false).

  • true — tak, prawidłowo, prawda, 1
  • false — nie, nieprawidłowo, fałsz, 0

Zwróć uwagę na nazwy zmiennych zawierających wartości logiczne. One najczęściej będą zadawać pytanie a ich wartość odpowiadać true lub false czyli prawda lub fałsz

            const isLoggedIn = true;
            const canMerge = false;
            const hasChildren = true;
            const isModalOpen = false;
          

null - specjalna wartość, która oznacza nic. Wykorzystujemy ją w sytuacjach, gdzie potrzebujemy wiedzieć, że nie istnieje jeszcze wartość, ale coś może się tam pojawić. Na przykład jeśli użytkownik nie wybrał żadnej z dostępnych opcji, to możemy przypisać wartość null.

            let selectedProduct = null;
          

undefined - specjalna wartość. Domyślnie, gdy zmienna jest zadeklarowana, ale nie zainicjalizowana, jej wartość jest niezdefiniowana, wtedy jej wartością jest określona jako undefined.

            let username;
            console.log(username);// undefined
          

Section18: Operator typeof

Służy do sprawdzenia typu wartości zmiennej. Pokazuje typ wartości zmiennej którą podamy

            let username;
            console.log(typeof username); // "undefined"

            let inputValue = null;
            console.log(typeof inputValue); // "object"

            const quantity = 17;
            console.log(typeof quantity); // "number"

            const message = "JavaScript is awesome!";
            console.log(typeof message); // "string"

            const isSidebarOpen = false;
            console.log(typeof isSidebarOpen); // "boolean"
          

Section19: Interakcja z użytkownikiem

Przeanalizujmy podstawowe operacje input/output używane do odbioru i wyświetlania danych od użytkownika, nie korzystając z HTML-a.

Section20: Output danych

Dla wyświetlania danych istnieją dwie metody: console.log() i alert(). W nawiasie wpisujemy nazwę zmiennej lub wartość, którą chcemy zobaczyć.

            const message = "JavaScript is awesome!";
            console.log(message); // JavaScript is awesome!
          

Czasem dla ułatwienia możemy wyświetlić kilka wartości naraz, w poniższym przykładzie mamy najpierw podany string opisujący nasz log, a następnie po przecinku wpisaną nazwę zmiennej.

            const username = "Mango";
            console.log("Username is ", username);// Username is Mango
          

Metoda alert() pokazuje okno modalne, które zawiera wartości zmiennej, którą przekażemy w nawiasie.

            const message = "JavaScript is awesome!";
            alert(message);
          

console i alert są częścią interfejsu window - obiektu globalnego, dostępnego podczas wykonywania skryptu na stronie internetowej. Wpisanie window.alert() jest zbędne, wystarczy po prostu alert() lub console.log(). Omówimy to bardziej szczegółowo w kolejnych modułach.

Going beyond console.log()

Section21: Otrzymanie danych

Aby uzyskać dane od użytkownika możemy użyć: prompt() i confirm(). To również są metody z interfejsu window. Jako wynik ich wywołania, zwracają to, co zostało wprowadzone przez użytkownika, następnie tę informację możemy zapisać do zmiennej i wykorzystać w przyszłości.

confirm() - pokazuje okno modalne i dwa przyciski Ok i Cancel. Przy kliknięciu na Ok, wynikiem będzie true, przy kliknięciu na Cancel - zwracana jest wartość false.

            // Prosimy klienta o potwierdzenie rezerwacji hotelu
            // i zapisujemy te dane do zmiennej przy kliknięciu confirm
            const isComing = confirm("Please confirm hotel reservation");
            console.log(isComing); // true lub false
          

Przykład -------------------------------

const button_s21 = document.querySelector('button#button-s21');
const postsList_s21 = document.querySelector('ul#user-list-s21');

button_s21.addEventListener('click', ev => {
  const isComing = confirm('Please confirm hotel reservation');
  renderHtml_s21(isComing);
});

function renderHtml_s21(isComing) {
  const markup = `<li >
          <p><b>Method confirm:</b></p>
          <p>isComing: ${isComing}</p>
        </li>`;
  postsList_s21.innerHTML = markup;
}
          

    PrzykładEND -------------------------------

    prompt() - pokazuje okno modalne z polem do wprowadzenia i przyciski Ok i Cancel. Przy kliknięciu Ok, rezultatem będzie to, co wprowadził użytkownik, przy Cancel - zwracamy wartość null.

                // Pytamy o nazwę hotelu z którego chciałby skorzystać klient
                // i zapisujemy wartość do zmiennej jako rezultat wykorzystania prompt.
                const hotelName = prompt("Please enter desired hotel name");
                console.log(hotelName); // string wprowadzony przez użytkownika lub null
              

    Ważną cechą prompt jest to, że bez względu na to, co wprowadził użytkownik, zawsze zwróci się string (wiersz). Oznacza to, że jeśli użytkownik wpisał 5, to nie zostanie zwrócona liczba 5, ale string "5".

                const value = prompt("Please enter a number!");
                console.log(typeof value); // "string"
                console.log(value); // "5"
              

    Przykład -------------------------------

    const button_s21 = document.querySelector('button#button-s21');
    const postsList_s21 = document.querySelector('ul#user-list-s21');
    
    button_s21.addEventListener('click', ev => {
      const isComing = confirm('Please confirm hotel reservation');
      renderHtml_s21(isComing);
    });
    
    function renderHtml_s21(isComing) {
      const markup = `<li >
              <p><b>Method confirm:</b></p>
              <p>isComing: ${isComing}</p>
            </li>`;
      postsList_s21.innerHTML = markup;
    }
              

      PrzykładEND -------------------------------

      Section22: Matematyczne operatory

      Zasady operacji matematycznych nie różnią się od ogólnie znanych działań (również kolejność wykonywania działań i honorowanie nawiasów pozostaje takie samo). Operatory zwracają wartość jako wynik wyrażenia.

                  const x = 10;
                  const y = 5;
      
                  // Dodawanie
                  console.log(x + y); // 15
      
                  // Odejmowanie
                  console.log(x - y); // 5
      
                  // Mnożenie
                  console.log(x * y); // 50
      
                  // Dzielenie
                  console.log(x / y); // 2
      
                  // Reszta po dzieleniu
                  console.log(x % y); // 0
      
                  // Dodawanie i przypisanie
                  let value = 5;
      
                  // Skrócony zapis: value = value + 10;
                  value += 10;
                  console.log(value); // 15
                

      Warto zapamiętać terminy, które tutaj wykorzystujemy. + - * / % to operatory, a parametr z którym one są wykorzystywane - operandy.

      Section23: Operatory porównania

      Wykorzystuje się do porównania dwóch wartości. Rezultatem wykonania będzie zwrócony boolean - true lub false, czyli «tak» lub «nie».

      • a > b i a < b - większe / mniejsze
      • a >= b i a <= b - większe lub równe / mniejsze lub równe
      • a == b - równa się
      • a != b - nie równa się
      • a === b - ściśle równa się
      • a !== b - ściśle nie równa się
                  const x = 5;
                  const y = 10;
                  const z = 5;
      
                  console.log("x > y:", x > y);// false
                  console.log("x < y:", x < y);// true
                  console.log("x < z:", x < z);// false
                  console.log("x <= z:", x <= z);// true
                  console.log("x === y:", x === y);// false
                  console.log("x === z:", x === z);// true
                  console.log("x !== y:", x !== y);// true
                  console.log("x !== z:", x !== z);// false
                

      Section24: Operatory równości

      «Nieścisłe» operatory równości == i != wykonują szereg transformacji na zmiennych różnego typu, co może spowodować błędy, tym bardziej u początkujących. Używanie operatorów == i != jest złą praktyką.

                  // ❌ Źle
                  console.log(5 == "5");// true
                  console.log(5 != "5");// false
                  console.log(1 == true);// true
                  console.log(1 != true);// false
                

      Na następnym obrazku pokazana jest tabelka która pokazuje jak zadziała operator nieścisłego porównania.

      Dlatego, aby sprawdzić równość lub nierówność dwóch wartości, wykorzystują się tylko operatory === (ścisła równość) i ! == (ścisła nierówność), które nie wykonują transformacji typów operandów.

                  // ✅ Dobrze
                  console.log(5 === "5");// false
                  console.log(5 === 5);// true
                  console.log(5 !== "5");// true
                  console.log(5 !== 5);// false
                  console.log(1 === true);// false
                  console.log(1 !== true);// true
                

      W takim wypadku, wartość równa się tylko identycznej wartości (również pod względem typu). Przed sprawdzeniem nie odbywa się żadna transformacja. Porównywanie bardziej skomplikowanych typów danych (takich jak tablice) omówimy w dalszych modułach.

      Section25: Konwersja do liczby

      Wszystkie liczby w JavaScript, zarówno całkowite jak i zmiennoprzecinkowe mają typ Number.

      Większość operacji arytmetycznych i funkcji matematycznych konwertuje wartość do liczby automatycznie. Aby upewnić się, że używamy wartości jako liczby, możemy użyć funkcji Number(val), przekazując jako val to, co należy przekonwertować na liczbę.

      Jeśli wartości nie można przekonwertować na liczbę, wynikiem będzie specjalna wartość liczbową NaN (Not a Number). Podobnie działa przekształcenie w innych operatorach i funkcjach matematycznych.

      Operację zmiany typu zmiennej na inny nazywamy też czasem Cast, Rzutowaniem lub Parsowaniem

                  const valueA = "5";
                  console.log(Number(valueA)); // 5
                  console.log(typeof Number(valueA)); // "number"
      
                  const valueB = "random string";
                  console.log(Number(valueB)); // NaN
                  console.log(typeof Number(valueB)); // "number"
                

      Section26: Metody Number.parseInt() i Number.parseFloat()

      Te dwie metody czytają wiersz znak po znaku tak długo, jak znaki tworzą liczbę. W momencie napotkania znaku nie-liczbowego zwracane jest to co udało się przekonwertować lub NaN jeżeli już pierwszy znak był np. literą

      Metoda Number.parseInt() próbuje sparsować liczbę całkowitą ze stringa.

                  console.log(Number.parseInt("5px")); // 5
                  console.log(Number.parseInt("12qwe74")); // 12
                  console.log(Number.parseInt("12.46qwe79")); // 12
                  console.log(Number.parseInt("GBP5")); // NaN
                  console.log(Number.parseInt("qweqwe")); // NaN
                

      Metoda Number.parseFloat() próbuje sparsować liczbę zmiennoprzecinkową ze stringa (zwróćmy uwagę, że tylko kropka . jest rozumiana jako przecinek między częścią całkowitą a ułamkową).

                  console.log(Number.parseFloat("5px"));// 5
                  console.log(Number.parseFloat("12qwe74"));// 12
                  console.log(Number.parseFloat("12.46qwe79"));// 12.46
                  console.log(Number.parseFloat("qweqwe"));// NaN
                  console.log(Number.parseFloat("5,32"));// 5
                

      Section27: Sprawdzenie liczby

      Aby sprawdzić po rzutowaniu, czy wartość jest liczbą, możemy wykorzystać metodę Number.isNaN(val). Sprawdzi ona, czy to co sprawdzamy posiada wartość NaN czy nie. Metoda odpowiada na pytanie "Czy to jest Not A Number?" i zwraca odpowiedź :

      • true - jeśli wartość val to NaN
      • false - jeśli wartość val nie NaN

      Dla wszystkich wartości val oprócz NaN, przy przekazaniu w Number.isNaN(val) zwrócone zostanie false. Ta metoda nie próbuje przekształcić val na liczbę, a po prostu sprawdza czy coś ma wartość NaN.

                  const validNumber = Number("51");// 51
                  console.log(Number.isNaN(validNumber));// false
      
                  const invalidNumber = Number("qweqwe");// NaN
                  console.log(Number.isNaN(invalidNumber));// true
                

      Section28: Dodawanie zmiennoprzecinkowe

      Dodawanie liczb zmiennoprzecinkowych w JavaScript daje czasem niespodziewane efekty. Dla przykładu, 0.1 + 0.2 nie jest równe 0.3, wynik będzie nieco większy niż „0,3". Wszystko przez to, że komputer liczy w systemie binarnym.

      Liczba 0.1 w systemie binarnym jest nieskończonym ułamkiem, ponieważ w takim systemie nie możemy przechować dokładnego wyniku dzielenia 1/10. Wartości binarne nieskończonych ułamków są przechowywane tylko do określonego znaku, przez co powstaje błąd obliczeniowy. Gdy dodajemy 0.1 i 0.2, sumują się dwa ułamki okresowe, przez co pojawia się drobny błąd w obliczeniach.

                  console.log(0.1 + 0.2 === 0.3);// false
                  console.log(0.1 + 0.2);// 0.30000000000000004
                

      Oczywiście nie oznacza to, że dokładne obliczenia dla takich liczb są niemożliwe. jest kilka metod rozwiązania tego problemu.

      Można przekształcić je w liczby całkowite, mnożąc je przez N10, dodając, a później dzieląc rezultat również przez N10 w zależności od potrzebnej nam dokładności.

                  console.log(0.17 + 0.24);// 0.41000000000000003
                  console.log((0.17 * 100 + 0.24 * 100) / 100);// 0.41
                

      Innym sposobem jest dodanie do siebie wartości a następnie ograniczenie rezultatu tej operacji do określonego miejsca po przecinku za pomocą metody toFixed(). Sposób ten ma jednak wadę, ponieważ zwróci on string a nie number.

      W nawiasie, metodzie toFixed() podajemy ile miejsc po przecinku potrzebujemy

                  console.log(0.17 + 0.24);// 0.41000000000000003
                  console.log((0.17 + 0.24).toFixed(2));// "0.41"
                  console.log((0.17 + 0.24).toFixed(3));// "0.410"
                  console.log(typeof (0.17 + 0.24).toFixed(2));// "string"
                

      Section29: Klasa Math

      Jedna z wbudowanych klas udostępniająca zestaw metod do pracy z liczbami. Znajomość wszystkich metod na pamięć nie jest wymagana, ale należy znać te najbardziej przydatne.

                  // Math.floor(num) - zwraca największą całkowitą liczbę,
                  // mniejszą, lub równą podanej liczbie, czyli zaokrągla w dół.
                  console.log(Math.floor(1.7)); // 1
      
                  // Math.ceil(num) - zwraca najmniejszą całkowitą liczbę,
                  // większą, lub równą podanej liczbie, czyli zaokrągla w górę.
                  console.log(Math.ceil(1.2)); // 2
      
                  // Math.round(num) - zwraca wartość liczby,
                  // zaokrągloną do najbliższej liczby całkowitej
                  // wedle zasad znanych ze szkoły
                  console.log(Math.round(1.2)); // 1
                  console.log(Math.round(1.5)); // 2
      
                  // Math.max(num1, num2, ...) - zwraca największą liczbę z podanych
                  console.log(Math.max(20, 10, 50, 40)); // 50
      
                  // Math.min(num1, num2, ...) - zwraca najmniejszą liczbę z podanych
                  console.log(Math.min(20, 10, 50, 40)); // 10
      
                  // Math.pow(base, exponent) - operacja potęgowania
                  console.log(Math.pow(2, 4)); // 2^4 === 16
      
                  // Math.random() - zwraca zmiennoprzecinkową liczbę pseudolosową 
                  // z zakresu [0, 1]
                  console.log(Math.random()); // pseudolosowa losowa liczba pomiędzy 0 i 1
                  console.log(Math.random() * (10 - 1) + 1); // pseudolosowa liczba od 1 do 10
                

      Section30: Strings

      Wiersz (String) - jest to indeksowany ciąg znaków, zawarty w cudzysłów pojedynczy lub podwójny, [ ' ] lub [ " ]

                  const username = "Mango";
                

      Należy pamiętać, że indeksowanie elementów string zaczyna się od zera. Na przykład w stringu "JavaScript " litera "J" stoi na pozycji z indeksem 0, a "t" ma indeks 9.

      Treści wiersza nie można zmieniać, można go tylko przeczytać. Oznacza to, że nie możesz wziąć jakiegoś znaku i zamienić go, po tym jak string zostanie stworzony - zostanie on taki na zawsze. Możesz natomiast stworzyć zupełnie nowy wiersz i przypisać go do tej samej zmiennej zamiast poprzedniej wartości.

      Section31: Konkatenacja wierszy

      Jeśli zastosujesz operator + pomiędzy string i dowolny inny typ danych, wynikiem operacji „dodawania" będzie nowy wiersz. Ta operacja nazywa się konkatenacją lub dodawaniem wierszy./p>

      Podczas konkatenacji dowolne typy danych są przetwarzane na string i łączą się z wierszem, natomiast co ważne - kolejność napisania operandów ma znaczenie w przeciwieństwie do operacji matematycznej.

      Kolejność ma znaczenie, ponieważ przekształcenie typów danych następuje tylko w momencie operacji dodawania z wierszem, w innych przypadkach rządzą zwykłe zasady matematyki.

                  const message = "Mango " + "is" + " happy";
                  console.log(message);// Mango is happy
                

      Zobaczmy różną kolejność operandów.

                  console.log(1 + "2");// "12"
                  console.log(1 + "2" + 4);// "124"
                  console.log(1 + 2 + "4");// "34"
                

      W ostatnim przykładzie odbyła się matematyczna operacja dodawania dla pierwszych dwóch liczb 1 oraz 2, po czym liczba 3 przekształciła się w wiersz "3" i została połączona z wierszem "4".

      Section32: Wiersze szablonowe

      Wiersze szablonowe są alternatywą dla konkatenacji z wygodniejszą składnią. Wiersz szablonu jest ujęty w grawisy, z angielskiego backticks - `` , zamiast podwójnych lub pojedynczych cudzysłowów i może zawierać wyrażenia, które są użyte przez znak dolara i nawiasy klamrowe ${wyrażenie}`.

                  // Używając zmiennych należy skomponować string z podstawionymi wartościami
                  const guestName = "Mango";
                  const roomNumber = 207;
                  const greeting =
                  "Welcome " + guestName + ", your room number is " + roomNumber + "!";
                  console.log(greeting);// "Welcome Mango, your room number is 207!"
                

      Komponowanie wierszy z wartościami określonymi za pomocą konkatenacji jest bardzo niewygodne. Na ratunek przychodzą wiersze szablonów.

                  const guestName = "Mango";
                  const roomNumber = 207;
                  const greeting = `Welcome ${guestName}, your room number is ${roomNumber}!`;
                  console.log(greeting);// "Welcome Mango, your room number is 207!"
                

      Section33: Właściwości i metody ciągów

      Każdy string ma swoje wbudowane właściwości i metody, zobaczmy jak działają niektóre z nich.

      Właściwość length

      Aby poznać długość wiersza, czyli liczbę jego znaków, dla wszystkich stringów istnieje wbudowana właściwość length, której wartość można uzyskać przez zwrócenie się do niej za pomocą kropki po nazwie zmiennej.

                  const message = "Welcome to Bahamas!";
                  console.log(message.length);// 19
                  console.log("There is nothing impossible to him who will try".length);// 47

      Metody toLowerCase() i toUpperCase()

      Zwracają nowy wiersz zastępując wszystkie litery odpowiednio małymi lub dużymi wersjami, nie zmieniając treści oryginalnej zmiennej.

      Cyfry i znaki specjalne nie zmieniają się.

                  const message = "Welcome to Bahamas!";
                  console.log(message.toLowerCase());// "welcome to bahamas!"
                  console.log(message.toUpperCase());// "WELCOME TO BAHAMAS!"
                  console.log(message);// "Welcome to Bahamas!"
                

      Zdarzają się sytuacje, w których wszystkie znaki w ciągu muszą zostać przekonwertowane na jedną wielkość liter, duże lub małe. Przykładem będzie wyszukiwanie po słowie kluczowym, użytkownik wpisuje wiersz 'saMsUng', który musi zostać porównany ze stringiem 'samsung' lub 'SAMSUNG'.

                  console.log("saMsUng" === "samsung");// false
                  console.log("saMsUng" === "SAMSUNG");// false
                

      Aby nie wymagać absolutnie dokładnych danych wejściowych, można wprowadzić «normalizację» wprowadzonego przez użytkownika wiersza, czyli przekonwertować wszystkie jego znaki na duże lub małe litery. Metody wierszy toLowerCase() i toUpperCase() zwrócą nowy wiersz w odpowiedniej postaci bez zmiany treści.

                  const BRAND_NAME = "SAMSUNG";
                  const userInput = "saMsUng";
                  const normalizedToUpperCaseInput = userInput.toUpperCase();
      
                  console.log(userInput);// 'saMsUng'
                  console.log(userInput === BRAND_NAME);// false
                  console.log(normalizedToUpperCaseInput);// 'SAMSUNG'
                  console.log(normalizedToUpperCaseInput === BRAND_NAME);// true
                

      Metoda indexOf()

      Zwraca pozycję (indeks), na której zaczyna się pierwsze dopasowanie podanego stringa lub -1 jeśli nigdzie takiego nie mamy. Wielkość liter jest tutaj istotna

                  const message = "Welcome to Bahamas!";
                  console.log(message.indexOf("to"));// 8
                  console.log(message.indexOf("To"));// -1
                  console.log(message.indexOf("hello"));// -1
                

      Metoda includes()

      Sprawdza, czy dany string jest zawarty w wierszu, (jest jego tak zwanym substringiem) zwraca boolean - true jeśli tak i false w przeciwnym wypadku. Dla tej metody również ważna jest wielkość liter, ponieważ litera "a" nie równa się literze "А".

                  const productName = "Repair droid";
      
                  console.log(productName.includes("p"));// true
                  console.log(productName.includes("P"));// false
                  console.log(productName.includes("droid"));// true
                  console.log(productName.includes("Droid"));// false
                  console.log(productName.includes("Repair"));// true
                  console.log(productName.includes("repair"));// false

      Wszystkie metody wierszy uwzględniają wielkość litery. Mówimy o nich, że są "case-sensitive"

      Metoda endsWith()

      Pozwala określić, czy wiersz kończy się określonym stringiem podanym w nawiasach, zwracając true lub false.

                  const jsFileName = "script.js";
                  console.log(jsFileName.endsWith(".js"));// true
      
                  const cssFileName = "styles.css";
                  console.log(cssFileName.endsWith(".js"));// false
                

      Metoda replace() i replaceAll()

      Zwraca nowy wiersz, w którym pierwsze (replace) lub wszystkie dopasowania (replaceAll) podanego stringa są zastępowane określoną wartością (w nawiasach po przecinku).

                  const jsFileName = "script.js";
                  const minifiedJsFileName = jsFileName.replace(".js", ".min.js");
                  console.log(minifiedJsFileName);// "script.min.js"
      
                  const cssFileNames = "styles.css, about.css, portfolio.css";
                  const minifiedCssFileNames = cssFileNames.replaceAll(".css", ".min.css");
                  console.log(minifiedCssFileNames);// "styles.min.css, about.min.css, portfolio.min.css"
                

      Metoda slice()

      Metodę string slice(startIndex, endIndex) wykorzystuje się do utworzenia kopii części lub całego łańcucha. Tworzy kopię elementów wiersza od znaku o indeksie startIndex i do, ale nie włączając w to znaku o indeksie podanym jako endIndex i zwraca nowy string.

                  const productName = "Repair droid";
                  console.log(productName.slice(0, 4)); // "Repa"
                  console.log(productName.slice(3, 9)); // "air dr"
                  console.log(productName.slice(0, productName.length)); // "Repair droid"
                  console.log(productName.slice(7, productName.length)); // "droid"
                

      Section34: Operatory logiczne

      Operatory logiczne służą do sprawdzenia warunków z wieloma wyrażeniami, na przykład operacjami porównania.

      Konwertowanie typu

      W operacjach logicznych typy operandów są konwertowane na true lub false. Konwersja występuje, gdy w kodzie zostanie znaleziony operator logiczny.

      Truthy i Falsy - terminy używane dla tych wartości, które w operacji logicznej są konwertowane na true lub false, chociaż jako takie nie miały typu boolean.

      Istnieje 6 nieprawdziwych (false) wartości, które sprowadzają się do false (są falsy) w logicznej konwersji: 0, NaN, null, undefined, pusty string czyli "" i false. Wszystkie inne wartości sprowadzają się do true (są truthy).

      Operatory logiczne

      W JavaScript Istnieją trzy operatory logiczne, które służą do sprawdzania wyrażeń.

      Logiczne «AND»(i)

      Operator && sprowadzi wszystkie operandy do typu boolean i zwraca 'true' jeśli wszystkie operandy są prawdziwe. Operandy są sprawdzane w kolejności zapisu, więc jeśli lewy warunek jest false, prawy już nie będzie sprawdzany a całość wyrażenia zwróci false.

                  wyrażenie && wyrażenie
                

      W poniższym przykładzie oba warunki zwrócą true, więc wynikiem całego wyrażenia będzie true - zostanie zwrócona wartość skrajnego prawego operandu.

                  const age = 20;
                  console.log(age > 10 && age < 30);// true && true -> true
                

      Jeśli chociażby jeden z operandów będzie false, rezultat wyrażenia otrzyma jego wartość.

                  const age = 50;
                  console.log(age > 10 && age < 30);// true && false -> false
                  console.log(age > 80 && age < 120);// false && true -> false
                

      Jak widzimy, logiczne «And(I)» szuka pierwszego operandu falsy i zwraca go, a jeśli go nie odnajdzie to zwróci ostatni w kolejności operand.

                  console.log(1 && 5);// true && true -> 5
                  console.log(5 && 1);// true && true -> 1
                  console.log(0 && 2);// false && true -> 0
                  console.log(2 && 0);// true && false -> 0
                  console.log("" && "Mango");// false && true -> ""
                  console.log("Mango" && "");// true && false -> ""
                  console.log("Mango" && "Poly");// true && true -> "Poly"
                  console.log("Poly" && "Mango");// true && true -> "Mango"
                

      Przy wykonaniu logicznego «AND», prawy operand może nie być sprawdzony, jeśli lewy doprowadzi do false.

      Logiczne «LUB(OR)»

      Operator || konwertuje wszystkie operandy do typu boolean i zwraca wartość 'true' jeżeli chociaż jeden jest prawdziwy. Lewy operand, jeśli można go przekształcić na true, i prawy operand w przeciwnych wypadkach.

                  wyrażenie || wyrażenie
                

      W poniższym przykładzie warunek po lewej stronie zwróci true, więc wynik całego wyrażenia będzie true - zostanie zwrócona wartość pierwszego operandu, który po wykonaniu go pokaże true.

                  const age = 5;
                  console.log(age < 10 || age > 30);// true || false -> true
                

      Tutaj wynik też będzie true, ponieważ jeden z operandów, w tym wypadku ten po prawej po wykonaniu równał się true.

                  const age = 40;
                  console.log(age < 10 || age > 30);// false || true -> true
                

      W kolejnym przykładzie żaden warunek nie był spełniony, dlatego otrzymujemy false - wartość ostatniego operanda.

                  const age = 20;
                  console.log(age < 10 || age > 30);// false || false -> false
                

      Oznacza to, że logiczne «OR» wyłapuje pierwszą prawdę/wartość truthy i zwraca tę wartość lub ostatni w kolejności operand.

                  console.log(true || false);// true
                  console.log(false || true);// true
                  console.log(true || true);// true
      
                  console.log(3 || false);// 3
                  console.log(false || 3);// 3
                  console.log(3 || true);// 3
                  console.log(true || 3);// true
                

      Przy wykonaniu logicznego «OR», prawy operand niekoniecznie musi być sprawdzony, jeśli lewy już był sprowadził się do true.

      Logiczne «NO»

      Wszystkie operatory, które omówiliśmy wcześniej, były binarne - zawierały dwa operandy, lewy i prawy. Logiczne "NIE" jest operatorem jednoargumentowym - operacje wykonują się na jednym operandzie po prawej stronie.

                  !wyrażenie
                

      Operator ! konwertuje operand do typu boolean, jeśli jest to koniecznie. Później odbywa się inwersja - zmienia jego znaczenie na odwrotne true -> false lub false -> true.

                  console.log(!true);// false
                  console.log(!false);// true
                  console.log(!3);// !3 -> !true -> false
                  console.log(!"Mango");// !"Mango" -> !true -> false
                  console.log(!0);// !0 -> !false -> true
                  console.log(!"");// !"" -> !false -> true
                  const isOnline = true;
                  const isNotOnline = !isOnline;// !isOnline -> !true -> false