jakubszpil

Renesans w JS, czyli nowoczesny JavaScript

JavaScript to wszechstronny język programowania, kluczowy dla współczesnych aplikacji webowych i nie tylko. Wraz z pojawieniem się standardu ES6 (ECMAScript 2015) oraz kolejnych aktualizacji, JS stał się bardziej ekspresyjny, bezpieczny i wygodny w użyciu. W tym przewodniku poznasz najważniejsze zagadnienia nowoczesnego JavaScriptu, które pozwolą Ci pisać czytelny, skuteczny i łatwo rozwijalny kod.

>>Spis treści

  1. Zmienne: let, const i zakresy blokowe
  2. Funkcje strzałkowe i ich zastosowania
  3. Szablony stringów (Template Literals)
  4. Destrukturyzacja tablic i obiektów
  5. Spread i rest operator (...)
  6. Promise API i obsługa asynchroniczności
  7. Async/await – nowoczesna obsługa kodu asynchronicznego
  8. Zadania do wykonania

>>Zmienne: let, const i zakresy blokowe

>>>Zakres blokowy (block scope)

W przeciwieństwie do starszego var, deklaracje let i const są ograniczone do bloku, w którym zostały zadeklarowane (czyli do najbliższych { ... }). Dzięki temu unikasz tzw. „przecieków zmiennych” (variable hoisting) i niezamierzonych nadpisań.

if (true) {
  let x = 5;
  const y = 10;
  console.log(x); // 5
}
// console.log(x); // ReferenceError

>>>Różnice między let, const i var

const tablica = [1, 2, 3];
tablica.push(4); // Dozwolone! Zmieniamy zawartość, nie referencję.
// tablica = [1, 2]; // Błąd! Przypisanie nowej referencji jest niedozwolone.

>>Funkcje strzałkowe i ich zastosowania

>>>Składnia funkcji strzałkowej

const dodaj = (a, b) => a + b;
const powitanie = (imie) => `Cześć, ${imie}!`;

>>>Funkcje strzałkowe a kontekst this

Funkcje strzałkowe nie mają własnego this, przez co bardzo dobrze sprawdzają się w metodach, callbackach czy w obsłudze zdarzeń, gdzie chcemy korzystać z kontekstu obiektu nadrzędnego.

function Timer() {
  this.sekundy = 0;
  setInterval(() => {
    this.sekundy++;
    console.log(this.sekundy);
  }, 1000);
}
new Timer(); // this.sekundy będzie poprawnie zwiększane

>>Szablony stringów (Template Literals)

>>>Interpolacja i wielolinijkowość

Szablony stringów pozwalają na interpolację zmiennych i wyrażeń oraz łatwe tworzenie tekstów wielolinijkowych, co jest szczególnie przydatne np. przy generowaniu HTML-a lub komunikatów:

const imie = "Ola";
const wiek = 25;
const info = `Mam na imię ${imie} i mam ${wiek} lat.`;
console.log(info);

const html = `
<div>
  <h1>${imie}</h1>
  <p>Wiek: ${wiek}</p>
</div>
`;

>>>Dodatkowe możliwości

Szablony stringów wspierają także tzw. tagowane szablony (tagged templates), które pozwalają na zaawansowaną manipulację tekstem (np. do tłumaczeń, walidacji, formatowania).

function upper(strings, ...values) {
  return strings[0] + values.map((v) => v.toUpperCase()).join("");
}
const imie = "Ania";
console.log(upper`Cześć, ${imie}!`); // Cześć, ANIA!

>>Destrukturyzacja tablic i obiektów

>>>Destrukturyzacja tablic

Pozwala na szybkie przypisanie wartości z tablicy do zmiennych:

const [pierwszy, drugi, trzeci = 0] = [10, 20];
console.log(pierwszy, drugi, trzeci); // 10 20 0 (wartość domyślna)

Można pomijać niektóre elementy lub korzystać z reszty:

const [a, , b, ...reszta] = [1, 2, 3, 4, 5];
console.log(a, b, reszta); // 1 3 [4, 5]

>>>Destrukturyzacja obiektów

Do zmiennych przypisywane są wartości na podstawie nazw kluczy:

const osoba = { imie: "Jan", wiek: 30, kraj: "PL" };
const { wiek, imie, miasto = "nieznane" } = osoba;
console.log(imie, wiek, miasto); // Jan 30 nieznane

Można zmieniać nazwy zmiennych:

const { imie: name, wiek: age } = osoba;
console.log(name, age); // Jan 30

>>Spread i rest operator (...)

>>>Spread operator

Pozwala na rozwinięcie (skopiowanie) elementów tablicy lub właściwości obiektu:

const tablica = [1, 2, 3];
const nowaTablica = [...tablica, 4, 5]; // [1, 2, 3, 4, 5]

const obiekt = { a: 1, b: 2 };
const nowyObiekt = { ...obiekt, c: 3 }; // { a: 1, b: 2, c: 3 }

>>>Rest operator

Pozwala na zbieranie wielu wartości w jedną tablicę (lub obiekt):

function suma(...liczby) {
  return liczby.reduce((a, b) => a + b, 0);
}
console.log(suma(1, 2, 3, 4)); // 10

const { a, ...reszta } = { a: 1, b: 2, c: 3 };
console.log(reszta); // { b: 2, c: 3 }

>>Promise API i obsługa asynchroniczności

>>>Czym jest Promise?

Promise reprezentuje operację asynchroniczną, która może zakończyć się sukcesem (resolve) lub błędem (reject). Stany: pendingfulfilled lub rejected.

const obietnica = new Promise((resolve, reject) => {
  setTimeout(() => {
    const sukces = Math.random() > 0.5;
    if (sukces) resolve("Sukces!");
    else reject("Błąd!");
  }, 1000);
});

obietnica
  .then((wynik) => console.log(wynik))
  .catch((błąd) => console.error(błąd))
  .finally(() => console.log("Gotowe!"));

>>>Łańcuchy Promise

Możesz łączyć wiele operacji asynchronicznych w łańcuch:

fetch("https://jsonplaceholder.typicode.com/users/1")
  .then((response) => response.json())
  .then((user) => console.log(user))
  .catch((error) => console.log(error));

>>Async/await – nowoczesna obsługa kodu asynchronicznego

>>>Uproszczenie pracy z Promise

Słowa kluczowe async i await pozwalają pisać kod asynchroniczny w stylu synchronicznym, co znacząco poprawia czytelność i obsługę błędów.

async function pobierzDane() {
  try {
    const response = await fetch(
      "https://jsonplaceholder.typicode.com/posts/1"
    );
    const post = await response.json();
    console.log(post);
  } catch (error) {
    console.error("Błąd:", error);
  }
}
pobierzDane();

>>>Zwracanie wartości i obsługa błędów

Wartość zwrócona przez funkcję oznaczoną async jest automatycznie opakowana w Promise.

async function zwrocLiczbe() {
  return 42;
}
zwrocLiczbe().then((val) => console.log(val)); // 42

Obsługa błędów działa z użyciem standardowego try...catch.


>>Zadania do wykonania

>>>Zadanie 1

Napisz funkcję strzałkową, która przyjmuje dowolną liczbę argumentów i zwraca ich sumę.

Pokaż rozwiązanie
const suma = (...args) => args.reduce((a, b) => a + b, 0);
console.log(suma(1, 2, 3)); // 6

>>>Zadanie 2

Utwórz obiekt reprezentujący użytkownika z kluczami: imie, email, aktywny. Następnie użyj destrukturyzacji, by wyodrębnić te wartości i wyświetlić je w konsoli.

Pokaż rozwiązanie
const user = { imie: "Ewa", email: "ewa@example.com", aktywny: true };
const { imie, email, aktywny } = user;
console.log(imie, email, aktywny); // Ewa ewa@example.com true

>>>Zadanie 3

Stwórz tablicę imion, a następnie utwórz nową tablicę ze wszystkimi tymi imionami plus dodatkowym imieniem na końcu (wykorzystaj spread).

Pokaż rozwiązanie
const imiona = ["Anna", "Bartek"];
const wiecejImion = [...imiona, "Celina"];
console.log(wiecejImion); // ["Anna", "Bartek", "Celina"]

>>>Zadanie 4

Napisz funkcję asynchroniczną, która symuluje pobieranie danych z serwera (z użyciem setTimeout i Promise) i po 2 sekundach wyświetla wynik.

Pokaż rozwiązanie
const pobierzDane = () =>
  new Promise((resolve) => setTimeout(() => resolve("Dane pobrane!"), 2000));

const asyncFunction = async () => {
  console.log("Pobieram dane...");
  const dane = await pobierzDane();
  console.log(dane);
};

asyncFunction();

To tylko początek przygody z nowoczesnym JavaScriptem! Zachęcam do dalszego zgłębiania m.in. takich zagadnień jak: klasy ES6, moduły, funkcje wyższego rzędu, obsługa błędów, praca z API, a także frameworków opartych na JS (React, Vue, Svelte).

Quiz: Podstawy nowoczesnego JavaScript

Pytanie 1 z 5

Jaką główną różnicę między let a var podkreśla się w nowoczesnym JavaScript?

Widzisz jakiś błąd, bądź literówkę? Chcesz coś poprawić?✏️ Przejdź do edycji tego pliku