JS cz.4

TRY CATCH

Opcjonalny blok: Try catch – konstrukcja, która sprawdza czy daną funkcję da się wykonać, jeżeli da się – wykonuje, jeśli nie – wywołuje obiekt Error, errora,to pełnoprawny blok kodu – ale nie powinno owijać nim całego programu, będzie wtedy maskować błędu – trzeba go używać w przypadkach kiedy mamy nieufność do użytkownika, ładowanie plików, styczność „ze światem zewnętrznym” – wtedy kiedy może się coś wysypać

Instrukcja try–catch (w językach takich jak Java, C#, JavaScript, Python – choć tam jest try–except) służy do obsługi wyjątków, czyli błędów, które mogą pojawić się podczas wykonywania programu.

try{
    const obiekt = null;
    console.log(obiekt.wlasciwosc); // To wywoła TypeError
} catch (error) {
    console.error("Wystąpił błąd:", error.message);
}
console.log("Program kontynuuje działanie po obsłudze błędu.");

PO try catch kolejne linijki kodu będą dalej czytane!!!

Ten obiekt ma właściwości – otrzymujemy je w kluczu massage
To obsługuje potencjalne błędy (3 rodzaje kategorii błędów – złe dane od użytkownika, niewykonanie operacji – bo nie było zasobów, nie istnieją zasoby – była awaria i nie ma pliku). Łapiemy te błędy, które umiemy obsłużyć.
WAŻNE w JS dzielenie przez 0 wywołuje NaN a nie Error – try catch na dzieleniu przez 0 nie zadziała

  1. Blok try
    W tym bloku umieszczasz kod, który może potencjalnie spowodować błąd.
  2. Blok catch
    Jeśli w bloku try wystąpi wyjątek, program przeskoczy do bloku catch i wykona znajdujący się tam kod zamiast przerwać działanie.
  3. (Opcjonalnie) blok finally
    Kod w finally wykona się zawsze, niezależnie od tego, czy pojawił się błąd, czy nie — zwykle używany do sprzątania zasobów (np. zamykanie plików).

Po co się tego używa?
• żeby nie wywalać programu przy błędach
• żeby elegancko obsługiwać sytuacje problemowe (np. brak pliku, błąd połączenia)
• żeby przechwytywać różne typy błędów (różne catch)

Try…catch łapie:
• wszystkie standardowe błędy JS (TypeError, ReferenceError, itd.)
• Twoje własne błędy (throw new Error())
• dowolne wartości, które „rzucisz” (throw 123)
• błędy w async/await, jeśli użyjesz go z try…catch
• błędy składni tylko wewnątrz eval
Try…catch NIE łapie:
• błędów składni kodu ładowanego normalnie
• błędów asynchronicznych poza blokiem catch


Syntax error – błąd składni – zwykle vs code podreśli lub wyświetli przy uruchamianiu programu

Range error – np. za głęboka rekurencja, wyjście poza zakres danych


THIS

this – słowo kluczowe dla JS ale mylące, to wartość (dopisywana do zmiennej) określona przez sposób wywołania funkcji, to referencja do kontekstu funkcji, który może się zmienić (bo funkcja może być wywołana np. jako konstruktor)

Jest 5 głównych kontekstów, są określone wartości wywoływane przez this dla każdej z nich

Globalny - wywołuje: obiekt window, który opisuje okno przeglądarki

Funkcji – jeśli wołam this w funkcji i nie mam innego kontekstu, żadnej wartości, argumentu – to również otrzymam window

*jeśli mam tryb dla funkcji ustawiony na ‘use strict” – dostanę undefined

*jeśli wołamy w funkcji zagnieżdżonej, wewnętrznej – dostanę window (bo nie mam argumentu, więc będzie odwołanie globalne)

*jeśli przekazujemy funkcję do funkcji – globalnie window, ale this zmieni się na: pokaż this

Metody -metodę wywołuje z zewnątrz obiektu, this- wskaże obiekt / tu jakiś problem 17:51

Konstruktora - wywołuje nowoutworzony obiekt

Funkcja strzałkowa - dzidziczy this z otoczenia

Kontekstthis wskazuje na…
Globalnyobiekt globalny (window/global)
Zwykła funkcjaobiekt wywołujący / undefined w strict
Metoda obiektuobiekt, który wywołał metodę
Konstruktor / klasynowo utworzony obiekt
Funkcja strzałkowadziedziczy this z otoczenia

this w event handlerze (event handler (ang. „obsługiwacz zdarzeń”) to funkcja, która zostaje wywołana, gdy wystąpi określone zdarzenie, np. kliknięcie myszką, wpisanie tekstu, scrollowanie strony.)

Jeśli używasz zwykłej funkcji (function(event) {}), this wskazuje na element, który wywołał zdarzenie (np. przycisk).

this nie ma specjalnej składni – jest to po prostu słowo kluczowe w JavaScript, które automatycznie wskazuje na kontekst wywołania funkcji.

const obj = {
  name: "Ala",
  sayName() {
    console.log(this.name);
  }
};

obj.sayName(); // Ala

this pozwala funkcji lub metodzie wiedzieć, „kto ją wywołał” – czyli działa w zależności od kontekstu. Bez tego trudno byłoby pisać uniwersalne funkcje i metody, które działają na różnych obiektach.

const person = {
  name: "Ala",
  greet() {
    console.log("Cześć, mam na imię " + this.name);
  }
};

person.greet(); // Cześć, mam na imię Ala
  • this.name pozwala metodzie greet wiedzieć, do którego obiektu należy.
  • Dzięki temu możesz mieć wiele obiektów z tą samą metodą, a metoda zawsze użyje właściwego name.

Chaining metod, gettery i settery – łączą się z this, bo wszystkie działają w kontekście obiektu, na którym są wywoływane:

Chaining metod (łańcuchowanie metod)

Chaining polega na wywoływaniu wielu metod jedna po drugiej na tym samym obiekcie, dzięki temu, że metoda zwraca this.

const obj = {
  value: 0,
  add(x) {
    this.value += x;
    return this; // zwracamy obiekt, żeby móc łańcuchować
  },
  multiply(x) {
    this.value *= x;
    return this;
  }
};

obj.add(2).multiply(3); // chaining
console.log(obj.value); // 6

Dlaczego this jest ważne?

  • Metoda zwraca this, czyli ten sam obiekt, więc możesz dalej wywoływać kolejne metody na nim.

Gettery (get)

  • Getter pozwala pobierać właściwość obiektu tak, jakby to była zwykła zmienna, ale pod spodem może wykonywać logikę.
  • this w getterze wskazuje na obiekt, którego właściwość pobierasz.
const person = {
  firstName: "Ala",
  lastName: "Nowak",
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
};

console.log(person.fullName); // Ala Nowak

tu his.firstName i this.lastName odnoszą się do obiektu person.

Settery (set)

  • Setter pozwala ustawiać właściwość obiektu, ale możesz przy tym wykonać dodatkową logikę.
  • this w setterze również wskazuje na obiekt, którego właściwość ustawiasz.
Settery (set)

Setter pozwala ustawiać właściwość obiektu, ale możesz przy tym wykonać dodatkową logikę.

this w setterze również wskazuje na obiekt, którego właściwość ustawiasz.

PODSUMOWANIE:

Chaining metod → this pozwala zwracać obiekt i wywoływać kolejne metody.

Getter → this pozwala pobierać dane z obiektu, w którym jesteśmy.

Setter → this pozwala modyfikować dane w tym samym obiekcie.


METHOD SHORTHAND (ES6)

W kontekście JavaScript, termin “shorthand” odnosi się do skróconego zapisu kodu, który pozwala pisać te same rzeczy w bardziej zwięzły sposób. Chodzi głównie o skróty składniowe w deklaracjach, przypisaniach i funkcjach

const o = { x() {} }

const o = {
  x: function() {
    console.log("Hello");
  }
};
const o = {
  x() {
    console.log("Hello");
  }
};

TABLICE

  1. sposób literał – wypisanie wartości krok po kroku
    -w jednej tablicy możemy trzymać różne typy elementów / tzw. mieszana
const arr = [1, 2, 3];
  1. konstruktor / new Array () – to jest pusta tablica z konstruktora
const arr = new Array(3); // pusta tablica o długości 3
const arr2 = new Array(1, 2, 3); // tablica z elementami
  1. tworzenie tablicy z podanych elementów
const arr = Array.of(1, 2, 3); // [1, 2, 3]
  1. tworzenie tablicy z iterowane obiektu
const str = "abc";
const arr = Array.from(str); // ["a", "b", "c"]

1 tworzenie tablicy o określonym rozmiarze

        const rozmiarTablicy = new Array(5); // tablica z 5 pustymi miejscami
        console.log("Tablica o rozmiarze 5:", rozmiarTablicy);
        console.log("Długość tablicy:", rozmiarTablicy.length);

        const tablicaJedenEl = new Array("5");
        console.log("Tablica z jednym elementem '5':", tablicaJedenEl);

METOY TABLICOWE

W JavaScript metody tablicowe to funkcje, które pozwalają łatwo operować na tablicach: przeglądać, zmieniać, filtrować, mapować i łączyć elementy

Metoda

Co robi?

Gdzie?

Co zwraca?

push()

dodaje

na koniec

nową długość

pop()

usuwa

z końca

usunięty element

shift()

usuwa

z początku

usunięty element

unshift()

dodaje

na początku

nową długość

// 1. PUSH - dodaj na koniec
        const owoce = ["jabłko", "banan"];
        console.log("Przed push:", owoce);

        const nowaDlugosc = owoce.push("pomarańcza");
        console.log("Po push:", owoce);
        console.log("Nowa długość:", nowaDlugosc); // 3

        // Push wielu elementów
        owoce.push("gruszka", "śliwka");
        console.log("Po wielu push:", owoce);

// 2. POP - usuń z końca
        const warzywa = ["marchew", "brokuł", "pomidor"];
        console.log("Przed pop:", warzywa);

        const usuniety = warzywa.pop();
        console.log("Usunięty:", usuniety); // "pomidor"
        console.log("Po pop:", warzywa);

        // Pop z pustej tablicy
        const pusta = [];
        const usunPusty = pusta.pop();
        console.log("Pop z pustej:", usunPusty); // undefined

// 3. SHIFT - usuń z początku
        const liczby = [1, 2, 3, 4, 5];
        console.log("Przed shift:", liczby);

        const pierwszy = liczby.shift();
        console.log("Usunięty pierwszy:", pierwszy); // 1
        console.log("Po shift:", liczby);


// 4. UNSHIFT - dodaj na początek
        const kolory = ["zielony", "niebieski"];
        console.log("Przed unshift:", kolory);

        const nowaDl = kolory.unshift("czerwony");
        console.log("Po unshift:", kolory);
        console.log("Nowa długość:", nowaDl);

        // Unshift wielu elementów
        kolory.unshift("fioletowy", "żółty");
        console.log("Po wielu unshift:", kolory);

// Push jest szybszy - dodaje na koniec
        // Unshift jest wolniejszy - musi przesunąć wszystkie elementy

        const duza = [];
        console.time("push 10000");
        for (let i = 0; i < 10000; i++) {
            duza.push(i);
        }
        console.timeEnd("push 10000");

        const duza2 = [];
        console.time("unshift 10000"); // Mniej bo wolniejsze
        for (let i = 0; i < 10000; i++) {
            duza2.unshift(i);
        }
        console.timeEnd("unshift 1000");

WAŻNE

Tablica z przypisaną tablicą będzie dalej jedną i tą samą tablicą !!!!

  • Tablice (i obiekty) w JS są przechowywane w pamięci jako obiekty, a zmienne przechowują referencję do nich.
  • Przypisanie jednej tablicy do drugiej nie kopiuje jej, tylko tworzy drugi wskaźnik do tej samej tablicy.
  • Aby mieć niezależną kopię, trzeba jawnie skopiować tablicę.

METODY TABLICOWE CD.

Metoda Zwraca Uwagi
forEach nic (undefined) tylko wykonuje akcję
map nowa tablica każdy element przetwarzany
filter nowa tablica tylko elementy spełniające warunek
find element pierwszy pasujący element
reduce jedna wartość kumuluje/tablicę do wartości
  • forEach → robisz coś dla każdego elementu, nic nie zwraca.
  • map → tworzysz nową tablicę z przetworzonymi elementami.
  • filter → tworzysz nową tablicę, ale tylko z elementami spełniającymi warunek.
  • find → szukasz pierwszego pasującego elementu.
  • reduce → redukujesz tablicę do jednej wartości.
array.forEach(el => {/* coś robisz */});
array.map(el => /* zwracasz nowy element */);
array.filter(el => /* true/false */);
array.find(el => /* true/false */);
array.reduce((acc, el) => /* nowa wartość */, początkowa_wartość);
  • el → pojedynczy element tablicy
  • acc → accumulator w reduce - czyli zmienna, która „zbiera” wynik pośredni podczas przechodzenia po tablicy.
  • początkowa_wartość → np. 0 dla sumy
Metoda Co robi Przykład
find() pierwszy element spełniający warunek [1,2,3].find(x=>x>1)2
findIndex() indeks elementu [1,2].findIndex(x=>x>1)1
includes() czy tablica zawiera wartość [1,2].includes(2)true
indexOf() indeks wartości [1,2].indexOf(2)1
some() czy jeden spełnia warunek [1,2].some(x=>x>1)true
every() czy wszystkie spełniają warunek [1,2].every(x=>x>0)true

UWAGA kolejność ma znaczenie – jeśli mielibyśmy filtrowanie danych i mapowanie nowych wartości na dane to najpierw trzeba zrobić filtrowanie (bo zwróci mniej elementów), to się bardziej opłaca

TE I INNE

Grupa Metoda / Operator Co robi / opis
Dodawanie / usuwanie elementów push() dodaje elementy na końcu tablicy
pop() usuwa ostatni element
shift() usuwa pierwszy element
unshift() dodaje elementy na początku tablicy
splice(start, deleteCount, ...items) usuwa lub dodaje elementy w środku tablicy
slice(start, end) zwraca fragment tablicy, nie modyfikuje oryginału
fill(value, start?, end?) wypełnia tablicę wartością w podanym zakresie
copyWithin(target, start, end?) kopiuje fragment tablicy w inne miejsce w tej samej tablicy
Iteracja / przekształcanie forEach(callback) wykonuje funkcję dla każdego elementu (nie tworzy nowej tablicy)
map(callback) tworzy nową tablicę z przekształconymi elementami
filter(callback) tworzy nową tablicę z elementami spełniającymi warunek
reduce(callback, initialValue) redukuje tablicę do jednej wartości
reduceRight(callback, initialValue) redukuje tablicę od końca do jednej wartości
flatMap(callback) mapuje i spłaszcza wynik
Szukanie / sprawdzanie find(callback) zwraca pierwszy element spełniający warunek
findIndex(callback) zwraca indeks pierwszego elementu spełniającego warunek
some(callback) czy przynajmniej jeden element spełnia warunek
every(callback) czy wszystkie elementy spełniają warunek
includes(value) sprawdza, czy tablica zawiera wartość
indexOf(value) zwraca indeks pierwszego wystąpienia wartości
lastIndexOf(value) zwraca indeks ostatniego wystąpienia wartości
Łączenie / modyfikacja struktury concat(...arrays) łączy tablice w nową tablicę
join(separator) łączy elementy tablicy w string
reverse() odwraca kolejność elementów (modyfikuje tablicę)
sort([compareFunction]) sortuje elementy tablicy (rosnąco domyślnie, można podać funkcję)
toString() zamienia tablicę na string
toLocaleString() zamienia tablicę na string wg lokalizacji
Tablice wielowymiarowe / płaskie flat(depth?) spłaszcza tablicę wielowymiarową
Array.isArray(value) sprawdza, czy wartość jest tablicą
Dodatkowe narzędzia keys() zwraca iterator kluczy (indeksów) tablicy
values() zwraca iterator wartości tablicy
entries() zwraca iterator par [indeks, wartość]
findLast(callback) zwraca ostatni element spełniający warunek (nowa metoda ES2022)
findLastIndex(callback) zwraca indeks ostatniego elementu spełniającego warunek
Operator ... (spread) rozpakowuje elementy tablicy np. do nowej tablicy lub funkcji

SORT

array.sort((a, b) => /* coś */);
  • Domyślnie sortuje elementy jako stringi
  • Czasem wyniki są nieoczekiwane dla liczb: [10,2,1].sort()[1,10,2]

SORT Z COMPARE FUNCTION

array.sort((a, b) => /* coś */);

a i b — dwie kolejne wartości do porównania

Funkcja musi zwrócić liczbę:

< 0 → a przed b

0 → kolejność bez zmian

0 → b przed a


OBIEKTY

Obiekty to struktury danych złożone z par klucz–wartość.
Służą do przechowywania informacji o rzeczach, które mają różne właściwości.
Przykład: użytkownik, samochód, produkt itp.

Do czego służy literał obiektu?

  • szybkie tworzenie obiektów,
  • przechowywanie danych,
  • grupowanie powiązanych informacji,
  • dodawanie metod (funkcji wewnątrz obiektu).
const person = {
  name: "Ala",
  age: 20,
  greet() {
    console.log("Cześć!");
  }
};
  • klucz: wartość
  • klucze oddzielamy przecinkami
  • wartości mogą być: liczby, stringi, tablice, funkcje itd.

W obiekcie może być umieszczona tablica czy inny obiekt, funkcje (które jeśli są związane z obiektem nazywa się metodami – wtedy używają one słowa this).


Metoda obiektu = funkcja w środku obiektu, która mówi, co ten obiekt potrafi zrobić. Sposób zapisywania funkcji jako właściwości obiektu:

dodaj: function(liczba) {
    ...
}
const kalkulator = {
    wynik: 0,
    dodaj: function(liczba) {
        this.wynik = this.wynik + liczba; // kalkulator.wynik += liczba;
        return this.wynik;
    },
    odejmij: function(liczba) {
        this.wynik = this.wynik - liczba;
        return this.wynik;
    },
    pomnoz: function(liczba) {
        this.wynik = this.wynik * liczba;
        return this.wynik;
    },
    reset: function() {
        this.wynik = 0;
        return this.wynik;
    }
// Używanie metod
console.log("Start:", kalkulator.wynik); // Wyświetli: 0
kalkulator.dodaj(5);
console.log("Po dodaniu 5:", kalkulator.wynik); // Wyświetli: 5
kalkulator.pomnoz(3);
console.log("Po pomnożeniu przez 3:", kalkulator.wynik); // Wyświetli: 15
kalkulator.odejmij(5);
console.log("Po odjęciu 5:", kalkulator.wynik); // Wyświetli: 10
kalkulator.reset();
console.log("Po resecie:", kalkulator.wynik); // Wyświetli: 0

Najpierw tworzysz obiekt (a w nim zapisujesz metody), a dopiero później możesz je wywołać.

const ksiazka = {
    tytul: "Pan Tadeusz",
    autor: "Adam Mickiewicz",
    rok: 1834,
    liczbaStron: 500,
    ISBN10: "1234567890",
    kategoria: ["epopeja narodowa","rymowane"],
    changeISBN: function(newISBN) {
        this.ISBN10 = newISBN;
        console.log("obiekt po zmianie:", this);
        return true;
    }
};

if(ksiazka.changeISBN("0987654321")){
    console.log("Zmiana powiodła się");
} else {
    console.log("Zmiana nie powiodła się");
}
//ksiazka.changeISBN("0987654321");

To działa dokładnie tak samo jak z funkcjami:

  • najpierw „tworzysz” funkcję,
  • potem ją wywołujesz.

METODY OBIEKTU

Metoda Co robi Przykład
Object.keys(obj) Zwraca tablicę kluczy obiektu Object.keys({a:1,b:2}) // ["a","b"]
Object.values(obj) Zwraca tablicę wartości obiektu Object.values({a:1,b:2}) // [1,2]
Object.entries(obj) Zwraca tablicę [klucz, wartość] Object.entries({a:1,b:2}) // [["a",1],["b",2]]
Object.assign(target, ...sources) Kopiuje właściwości z obiektów źródłowych do celu Object.assign({}, {a:1},{b:2}) // {a:1,b:2}
Object.create(proto) Tworzy nowy obiekt z podanym prototypem Object.create(Array.prototype)
Object.freeze(obj) Blokuje modyfikację obiektu Object.freeze({a:1})
Object.seal(obj) Blokuje dodawanie/usuwanie właściwości (ale można zmieniać istniejące) Object.seal({a:1})
Object.is(value1, value2) Porównuje wartości jak ===, ale z lepszą obsługą NaN i -0 Object.is(NaN, NaN) // true
Object.getOwnPropertyNames(obj) Zwraca tablicę wszystkich własnych nazw właściwości (łącznie z nieenumerable) Object.getOwnPropertyNames({a:1}) // ["a"]
Object.getOwnPropertyDescriptors(obj) Zwraca opis właściwości (property descriptors) Object.getOwnPropertyDescriptors({a:1})
Object.hasOwn(obj, prop) Sprawdza, czy obiekt ma własną właściwość Object.hasOwn({a:1}, "a") // true
Object.defineProperty(obj, prop, descriptor) Definiuje lub zmienia właściwość z dokładnym opisem Object.defineProperty({}, "a",{value:1,writable:true})
Object.defineProperties(obj, descriptors) Definiuje wiele właściwości naraz Object.defineProperties(obj,{a:{value:1}})
Object.fromEntries(array) Tworzy obiekt z tablicy [klucz, wartość] Object.fromEntries([["a",1],["b",2]]) // {a:1,b:2}

🔹 Object.keys(obj)

Zwraca tablicę kluczy obiektu.
Służy do sprawdzania, jakie właściwości obiekt posiada.

🔹 Object.values(obj)

Zwraca tablicę wartości z obiektu.
Używamy, gdy interesują nas tylko dane, bez nazw kluczy.

🔹 Object.entries(obj)

Zwraca tablicę par [klucz, wartość].
Przydatne, gdy chcesz iterować po obiekcie w formie listy.

const person = {
  name: "Ala",
  age: 20,
  city: "Kraków"
};

console.log(Object.keys(person));   
// ["name", "age", "city"]

console.log(Object.values(person)); 
// ["Ala", 20, "Kraków"]

console.log(Object.entries(person)); 
// [["name","Ala"], ["age",20], ["city","Kraków"]]

estructuring (destrukturyzacja) obiektu w JS

  • Destrukturyzacja pozwala wyciągnąć właściwości obiektu do zmiennych w jednej linijce.
  • Dzięki temu nie trzeba pisać np. const x = obj.x; const y = obj.y;.

const { właściwość1, właściwość2 } = obiekt;

gdzie:

właściwość1, właściwość2 → nazwy właściwości obiektu, które chcemy „wyciągnąć”

obiekt → obiekt, z którego pobieramy wartości


Property descriptors to „ukryte ustawienia”, które opisują, jak zachowuje się dana właściwość obiektu w JavaScript.

Każda właściwość ma dodatkowe cechy, takie jak:

  • writable – czy można zmieniać wartość
  • enumerable – czy właściwość pokazuje się w pętli for...in lub w Object.keys()
  • configurable – czy można ją usunąć lub zmienić jej ustawienia
  • (opcjonalnie) get / set – funkcje pobierające i ustawiające wartość

To nie są rzeczy, które widzisz na co dzień — ale JavaScript używa ich pod spodem, by kontrolować działanie obiektów.


Klasy w JavaScripcie to specjalny sposób tworzenia obiektów i ich „szablonów”.

Prosto mówiąc:

  • Klasa to przepis na obiekt.
  • Na podstawie klasy możesz tworzyć wiele obiektów, które mają te same właściwości i funkcje (metody).

Po co są?

  • Żeby łatwo tworzyć wiele podobnych obiektów.
  • Żeby uporządkować kod, szczególnie gdy obiekty mają zachowania (metody).
  • Żeby kod był czytelniejszy i bardziej „poukładany”.

Syntax sugar – opakowanie na istniejący język prototypów (klasy: pod spodem prototypy – ale czytelniejsza składnia)

w klasach nie mówimy o prototypie ale o klasach, konstruktorach i instancjach klas

Konstruktor — „budowniczy” obiektu

Konstruktor to specjalna funkcja wewnątrz klasy, która uruchamia się automatycznie, gdy tworzysz obiekt na podstawie tej klasy.

To on:

  • przyjmuje dane (np. marka, model),
  • zapisuje je w obiekcie,
  • przygotowuje obiekt do działania.

W kodzie jest to funkcja o nazwie constructor().

Instancja — „konkretna sztuka” obiektu

Instancja (ang. instance) to konkretny obiekt stworzony na podstawie klasy.

Jeśli klasa jest przepisem, to instancja jest konkretnym daniem zrobionym według tego przepisu.

Podsumowanie w 1 zdaniu

  • Klasa – przepis
  • Konstruktor – kucharz przygotowujący potrawę
  • Instancja – gotowa potrawa

Klasy – świetne kiedy powtarzają się komponenty na stronach, klasa to rozwinięcie prototypu
Nazwa klasy jest zawsze z dużej litery (nie tak jak zmienne)/ Pascal Case
this → wskazuje na obiekt, który właśnie tworzysz albo którego używasz, używa się go dla każdej nowej instancji
new → zaczyna proces tworzenia nowego obiektu.

class Osoba {
  constructor(imie, wiek) {
    // this wskazuje na nowo tworzony obiekt
    this.imie = imie;
    this.wiek = wiek;
  }

  przywitaj() {
    // this wskazuje na obiekt, który wywołał tę metodę
    console.log(`Cześć, jestem ${this.imie} i mam ${this.wiek} lat.`);
  }
}

// użycie new — tworzymy nową instancję klasy
const osoba1 = new Osoba("Kasia", 25);

// metoda używa this — odnosi się do obiektu osoba1
osoba1.przywitaj();

Metody dla instancji tworzymy bez słowa function np. przywitaj() {}

UWAGA Klasy muszą być zadeklarowane przed ich użyciem!!!

Jak sięgnąć do właściwości konkretnych obiektów – posługując się zamienną, w której pojawiło się new.

Piszemy nazwę zmiennej – kropka – nazwa lub nazwa w nawiach[], jeśi jest zmienną np.:

osoba1.imie lub osoba1[‘Kasia’]

Jedna metoda dla klasy obsługuje wszystkie obiekty. Tworzenie metody dla klasy w JavaScript jest bardzo proste — po prostu dodajesz ją wewnątrz ciała klasy, ale poza konstruktorem.

Metoda to po prostu funkcja zapisana w klasie, która automatycznie ma dostęp do this (czyli właściwości obiektu).


Metody statyczne

Metody statyczne to takie metody w klasie, które należą do samej klasy, a nie do jej obiektów. Metoda statyczna = funkcja klasy, a nie funkcja obiektu.

❗ Metod statycznych NIE wywołujesz na obiekcie.

  • Metoda statyczna to narzędzie klasy,
    a nie „czynność” wykonywana przez konkretny obiekt.
  • Nie ma dostępu do this w sensie obiektu,
    bo nie działa na obiekcie.

Kiedy używać metod statycznych?

✔ Gdy metoda nie dotyczy konkretnego obiektu, tylko kategorii / klasy jako całości.


Przykłady:

  • funkcje matematyczne (suma, losowanie, zaokrąglanie) np. Math.random
  • tworzenie obiektów w specjalny sposób (fabryki- Fabryka obiektów to po prostu funkcja lub metoda, która tworzy i zwraca nowe obiekty. Mówiąc prosto: zamiast pisać wielokrotnie new Klasa(...), możesz mieć jedną funkcję, która automatycznie generuje obiekty według przepisu.)
  • porównywanie dwóch obiektów
  • narzędzia pomocnicze
Typ metody Deklaracja Wywołanie Przykład
Instancyjna bez static na obiekcie js class Person { greet() { console.log("Cześć"); } } const p = new Person(); p.greet();
Statyczna static na klasie js class MathUtils { static add(a,b){ return a+b; } } console.log(MathUtils.add(2,3));
Prywatna # przed nazwą tylko w klasie js class Secret { #show(){ return "tajne"; } reveal(){ console.log(this.#show()); } } const s = new Secret(); s.reveal(); // działa, s.#show(); ❌ błąd

Typ pola*

Dla kogo?

Jak dostęp?

zwykłe (this.imie)

dla obiektu

obiekt.imie

statyczne (static licznik)

dla klasy

Klasa.licznik

prywatne (#wiek)

dla klasy, wewnątrz metod

this.#wiek

Pole klasy = zmienna powiązana albo z obiektem, albo z klasą

-Przechowuje dane, które opisują obiekt (zwykłe) lub klasę (statyczne)

-Prywatne pola = dane ukryte, dostępne tylko w metodach klasy


W JavaScripcie super używa się w kontekście dziedziczenia klas.
Mówiąc prosto, pozwala odwołać się do rodzica klasy — zarówno do jego konstruktora, jak i do metod.

super() w konstruktorze

  • Gdy tworzysz klasę potomną (dziedziczącą), możesz użyć super(), żeby wywołać konstruktor klasy rodzica.
  • Dzięki temu nie musisz przepisywać kodu rodzica, tylko przekazujesz mu potrzebne dane.
  • Super występuje przed this?

W JavaScripcie, gdy klasa dziecka ma własny konstruktor i jeśli nie wywołasz super(), to:

  1. Konstruktor rodzica (Zwierze) nie zostanie uruchomiony.
  2. this w klasie dziecka nie istnieje jeszcze i próba ustawienia this.imie lub użycia this wyrzuci błąd.

Super istnieje w parze z extends:

-super w JS służy do wywołania konstruktora lub metod klasy rodzica.

-Klasa rodzica istnieje tylko wtedy, gdy używasz extends, czyli dziedziczenia.

// Klasa bazowa
class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} wydaje dźwięk`);
  }
}

// Klasa potomna dziedzicząca po Animal
class Dog extends Animal {
  constructor(name, breed) {
    super(name);       // wywołuje konstruktor klasy bazowej
    this.breed = breed;
  }

  speak() {
    super.speak();     // wywołuje metodę speak() z klasy bazowej
    console.log(`${this.name} szczeka`);
  }
}

const dog = new Dog("Burek", "Owczarek");
dog.speak();

Enkapsulacja (z ang. encapsulation) to zasada programowania obiektowego, która polega na ukrywaniu szczegółów wewnętrznych obiektu i udostępnianiu tylko tego, co jest potrzebne na zewnątrz.

Mówiąc prosto:

„Schowaj wewnętrzne dane i pozwól innym korzystać z nich tylko przez określone metody.”

Dlaczego to ważne?

  1. Chroni dane obiektu przed niepożądaną zmianą z zewnątrz.
  2. Pozwala kontrolować jak można modyfikować lub odczytywać dane.
  3. Ułatwia utrzymanie i rozwój kodu — zmiany wewnątrz klasy nie psują reszty programu, jeśli interfejs (metody) się nie zmienia.
class BankAccount {
  #balance = 0; // prywatna właściwość

  constructor(initialBalance) {
    this.#balance = initialBalance;
  }

  // publiczna metoda do wpłaty
  deposit(amount) {
    if(amount > 0) this.#balance += amount;
  }

  // publiczna metoda do sprawdzenia stanu konta
  getBalance() {
    return this.#balance;
  }
}

const account = new BankAccount(100);
account.deposit(50);
console.log(account.getBalance()); // 150

// Próba dostępu do prywatnego pola
console.log(account.#balance); // ❌ Błąd!

Cecha Metody klasy Metody obiektu
Gdzie są deklarowane W klasie (class) W obiekcie literalnym (const obj = { ... })
Do czego należą Do instancji lub do klasy (statyczne) Do konkretnego obiektu
Wywołanie - Instancyjne: obj.method() - Statyczne: Class.method() obj.method()
Tworzenie nowych instancji Można tworzyć wiele obiektów z tej samej klasy, wszystkie dzielą prototypowe metody Każdy obiekt literalny ma własne metody; nie są współdzielone automatycznie
Prywatność Prywatne metody #method dostępne tylko w klasie Prywatność zwykle symulowana przez zamknięcia (closure), brak wbudowanej składni # w starszych wersjach
Dziedziczenie extends pozwala tworzyć klasy potomne z tymi samymi metodami Trzeba ręcznie kopiować metody lub używać prototypów

Prototypy w JS – co to jest

  • Prototyp to obiekt, z którego inne obiekty dziedziczą właściwości i metody.
  • Każdy obiekt w JS ma ukryte powiązanie z innym obiektem – jego prototypem ([[Prototype]]).
  • Dzięki temu można współdzielić metody między wieloma obiektami, zamiast tworzyć je w każdym obiekcie osobno.
  1. Tworzysz obiekt:

const person = { name: "Ala" };

  1. Możesz sprawdzić jego prototyp:

console.log(Object.getPrototypeOf(person)); // np. Object.prototype

  1. eśli próbujesz użyć właściwości/metody, której obiekt nie ma, JS sprawdza prototyp i dalej w jego łańcuchu (chain), aż do null.

console.log(person.toString()); // działa, bo toString jest w Object.prototype


Składnia dodawania metod do prototypu

function Person(name) {
this.name = name;
}

// Dodanie metody do prototypu
Person.prototype.greet = function(
) {
console.log(`Cześć, mam na imię ${this.name}`);
};

const p = new Person("Ala");
p.greet(); // "Cześć, mam na imię Ala"

  • p nie ma własnej metody greet, ale dziedziczy ją z prototypu klasy/funkcji.