JavaScript nieustannie ewoluuje, wprowadzając nowe funkcje, które ułatwiają programistom tworzenie lepszych aplikacji. W tym artykule poznasz najważniejsze nowości wprowadzone w ECMAScript 2025 oraz dowiesz się, jak wykorzystać je w swoich projektach.

Record i Tuple - niezmienne struktury danych

Jedną z najbardziej oczekiwanych nowości w ES2025 są niezmienne struktury danych - Record i Tuple:

// Record - niezmienny obiekt
const person = #{
    name: "Anna",
    age: 30,
    city: "Warszawa"
};

// Tuple - niezmienne array
const coordinates = #[52.2297, 21.0122];

// Próba modyfikacji rzuci błąd
// person.name = "Maria"; // TypeError!

Te struktury oferują lepszą wydajność i bezpieczeństwo, szczególnie w aplikacjach React gdzie niezmienność jest kluczowa.

Pattern Matching - dopasowanie wzorców

Pattern matching to potężna funkcja znana z języków funkcyjnych, która w końcu trafia do JavaScript:

function processData(value) {
    match (value) {
        case { type: "user", name: String, age: Number } => {
            console.log(`Użytkownik: ${name}, wiek: ${age}`);
        }
        case { type: "product", price: Number } when price > 100 => {
            console.log("Drogi produkt");
        }
        case String if value.startsWith("http") => {
            console.log("To jest URL");
        }
        case Number => {
            console.log("To jest liczba");
        }
        default => {
            console.log("Nierozpoznany typ danych");
        }
    }
}

Temporal API - nowy sposób pracy z datami

Temporal API zastępuje problematyczny obiekt Date z nowoczesnymi, intuicyjnymi klasami:

// Aktualna data i czas
const now = Temporal.Now.plainDateTimeISO();

// Precyzyjna data
const birthday = Temporal.PlainDate.from('1990-05-15');

// Operacje na datach
const nextWeek = now.add({ days: 7 });
const duration = nextWeek.since(now);

console.log(duration.days); // 7

// Formatowanie
const formatted = now.toLocaleString('pl-PL', {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
});

Decorators - dekoratory w JavaScript

Dekoratory pozwalają na modyfikację klas i ich składników w elegancki sposób:

// Dekorator dla logowania
function logged(target, context) {
    return function(...args) {
        console.log(`Wywoływanie ${context.name} z argumentami:`, args);
        return target.apply(this, args);
    };
}

// Dekorator dla walidacji
function validate(validator) {
    return function(target, context) {
        return function(value) {
            if (!validator(value)) {
                throw new Error(`Nieprawidłowa wartość: ${value}`);
            }
            return target.call(this, value);
        };
    };
}

class User {
    constructor(name) {
        this.name = name;
    }

    @logged
    getName() {
        return this.name;
    }

    @validate(name => name.length > 2)
    setName(name) {
        this.name = name;
    }
}

Pipeline Operator - operator rurociągu

Pipeline operator (|>) znacznie poprawia czytelność kodu przy łączeniu funkcji:

// Tradycyjny sposób
const result = Math.round(Math.abs(Math.sqrt(16)));

// Z pipeline operator
const result = 16
    |> Math.sqrt
    |> Math.abs
    |> Math.round;

// Z funkcjami strzałkowymi
const processText = text => text
    |> (str => str.trim())
    |> (str => str.toLowerCase())
    |> (str => str.replace(/\s+/g, '-'))
    |> (str => str.substring(0, 50));

const slug = processText("  JavaScript ES2025 Nowości  ");

Import Assertions - asercje importu

Nowa składnia pozwala na bezpieczniejsze importowanie różnych typów plików:

// Import JSON
import config from './config.json' assert { type: 'json' };

// Import CSS
import styles from './styles.css' assert { type: 'css' };

// Import WebAssembly
import wasmModule from './calculate.wasm' assert { type: 'webassembly' };

// Dynamiczny import z asercją
const data = await import('./data.json', {
    assert: { type: 'json' }
});

Array.fromAsync - asynchroniczne tworzenie tablic

Nowa metoda do tworzenia tablic z asynchronicznych iteratorów:

async function* asyncGenerator() {
    for (let i = 0; i < 5; i++) {
        yield new Promise(resolve => 
            setTimeout(() => resolve(i * 2), 100)
        );
    }
}

// Tworzenie tablicy z async generatora
const results = await Array.fromAsync(asyncGenerator());
console.log(results); // [0, 2, 4, 6, 8]

// Z mapowaniem
const doubled = await Array.fromAsync(
    asyncGenerator(),
    x => x * 2
);
console.log(doubled); // [0, 4, 8, 12, 16]

Improved Error Cause - lepsze łączenie błędów

Nowe możliwości w konstruktorze Error pozwalają na lepsze śledzenie przyczyn błędów:

try {
    throw new Error("Błąd w API", { 
        cause: "Brak połączenia z serwerem" 
    });
} catch (error) {
    console.log(error.message); // "Błąd w API"
    console.log(error.cause); // "Brak połączenia z serwerem"
    
    // Ponowne rzucenie z dodatkowym kontekstem
    throw new Error("Błąd w aplikacji", { 
        cause: error 
    });
}

WeakRef i FinalizationRegistry - zaawansowane zarządzanie pamięcią

Nowe API do precyzyjnego kontrolowania garbage collection:

class ResourceManager {
    constructor() {
        this.registry = new FinalizationRegistry((heldValue) => {
            console.log(`Zwalnianie zasobu: ${heldValue}`);
            // Cleanup logic
        });
        this.resources = new Map();
    }
    
    createResource(id, data) {
        const resource = { id, data };
        const ref = new WeakRef(resource);
        
        this.resources.set(id, ref);
        this.registry.register(resource, id);
        
        return resource;
    }
    
    getResource(id) {
        const ref = this.resources.get(id);
        if (ref) {
            const resource = ref.deref();
            if (resource) {
                return resource;
            } else {
                // Obiekt został usunięty przez GC
                this.resources.delete(id);
            }
        }
        return null;
    }
}

String.prototype.at() - wygodniejszy dostęp do znaków

Nowa metoda pozwala na dostęp do znaków z użyciem indeksów ujemnych:

const text = "JavaScript";

// Tradycyjnie
console.log(text[text.length - 1]); // "t"

// Z metodą at()
console.log(text.at(-1)); // "t"
console.log(text.at(-2)); // "p"
console.log(text.at(0));  // "J"

// Działa również z tablicami
const arr = [1, 2, 3, 4, 5];
console.log(arr.at(-1)); // 5

Praktyczne zastosowania w projektach

1. Budowanie API klientów

class APIClient {
    @logged
    async fetchUser(id) {
        return fetch(`/api/users/${id}`)
            |> (response => response.json())
            |> (data => new User(data));
    }
    
    match(response) {
        case { status: 200, data: Object } => {
            return this.processSuccess(data);
        }
        case { status: 404 } => {
            throw new Error("Nie znaleziono użytkownika");
        }
        default => {
            throw new Error("Nieznany błąd API");
        }
    }
}

2. Walidacja danych formularzy

const validateForm = data => data
    |> (d => ({ ...d, email: d.email.trim().toLowerCase() }))
    |> (d => match(d) {
        case { email: String, age: Number } when d.age >= 18 => d,
        default => { throw new Error("Nieprawidłowe dane formularza"); }
    });

Wsparcie przeglądarek i narzędzia

Większość funkcji ES2025 jest już dostępna w:

  • Chrome 95+
  • Firefox 93+
  • Safari 15+
  • Node.js 18+

Do korzystania z najnowszych funkcji polecamy:

  • Babel - transpilacja kodu
  • TypeScript 4.8+ - wsparcie dla nowych funkcji
  • ESLint - reguły dla nowej składni

Podsumowanie

ECMAScript 2025 wprowadza rewolucyjne zmiany, które znacznie poprawiają wydajność, czytelność i bezpieczeństwo kodu JavaScript. Funkcje takie jak pattern matching, pipeline operator czy niezmienne struktury danych przybliżają JavaScript do języków funkcyjnych, zachowując jednocześnie jego elastyczność.

Aby w pełni wykorzystać potencjał nowoczesnego JavaScript, warto systematycznie śledzić zmiany w języku i stopniowo wprowadzać nowe funkcje do swoich projektów.

Chcesz nauczyć się nowoczesnego JavaScript? Sprawdź nasz kurs JavaScript i React, gdzie poznasz wszystkie najnowsze funkcje języka!