StriveLab
Strony internetowe
Usługi
RealizacjeO mnieBlogPorozmawiajmy
PL
EN

Astro

Ultraszybkie projekty, łączące lekkość ze skalowalnością.

Next.js

Elastyczne i wydajne narzędzia dla biznesu, które dotrzymają kroku Twojemu rozwojowi.

React

Połączenie intuicyjności z wydajnością, które zapewnia bezproblemową skalowalność kodu.

SEO & Performance

Audyt techniczny i optymalizacja pod kątem SEO i GEO.

Automatyzacja AI

Bezpieczne automatyzacje procesów i agenci AI w n8n, Make i Claude.

QA & Automation

Testy automatyczne komponentów i E2E w Cypress.

Doradztwo produktowe

Połączenie perspektywy produktu, developera i marketingu w jednym miejscu

StriveLab
Strony internetowe
Usługi
RealizacjeO mnieBlogPorozmawiajmy
PL
EN

Astro

Ultraszybkie projekty, łączące lekkość ze skalowalnością.

Next.js

Elastyczne i wydajne narzędzia dla biznesu, które dotrzymają kroku Twojemu rozwojowi.

React

Połączenie intuicyjności z wydajnością, które zapewnia bezproblemową skalowalność kodu.

SEO & Performance

Audyt techniczny i optymalizacja pod kątem SEO i GEO.

Automatyzacja AI

Bezpieczne automatyzacje procesów i agenci AI w n8n, Make i Claude.

QA & Automation

Testy automatyczne komponentów i E2E w Cypress.

Doradztwo produktowe

Połączenie perspektywy produktu, developera i marketingu w jednym miejscu

Astro

Ultraszybkie projekty, łączące lekkość ze skalowalnością.

Next.js

Elastyczne i wydajne narzędzia dla biznesu, które dotrzymają kroku Twojemu rozwojowi.

React

Połączenie intuicyjności z wydajnością, które zapewnia bezproblemową skalowalność kodu.

SEO & Performance

Audyt techniczny i optymalizacja pod kątem SEO i GEO.

Automatyzacja AI

Bezpieczne automatyzacje procesów i agenci AI w n8n, Make i Claude.

QA & Automation

Testy automatyczne komponentów i E2E w Cypress.

Doradztwo produktowe

Połączenie perspektywy produktu, developera i marketingu w jednym miejscu

RealizacjeO mnieBlog
Porozmawiajmy
PL
EN

Nowoczesne strony internetowe dla firm, które myślą odważnie.

Przewiń do góry

Nazwa

StriveLab Maciej Sala

NIP

6772218995

REGON

524008527

E-mail

contact@strivelab.pl

Usługi główne
  • Tworzenie stron internetowych
  • Strony internetowe Next.js
  • Strony internetowe Astro
  • Strony internetowe React
Inne usługi
  • Usługi
  • SEO & Performance Sprint
  • QA & Stabilizacja
  • Konsultacje Product / Delivery
  • Automatyzacja Procesów AI
  • Aplikacje webowe Next.js
  • Współpraca ciągła
Strony
  • O mnie
  • Usługi
  • Realizacje
  • Blog

© 2026 StriveLab.pl

Polityka prywatności
JavaScript

10 sztuczek w JavaScript, które sprawią, że Twój kod będzie 10x czytelniejszy

Poznaj 10 technik JavaScript, które realnie poprawiają czytelność kodu. Optional chaining, nullish coalescing, destrukturyzacja, metody tablic i więcej.

OpublikujLinkedInFacebookWyślij
Autor
Maciej Sala
Opublikowano
12 czerwca 2025 12:23
Czytanie
5 min czytania
Aktualizacja
26 maja 2026 10:37

Czytelny kod rzadko powstaje dzięki wielkiemu refaktorowi, a zwykle wynika z małych decyzji podejmowanych codziennie: jak obsługujesz brakujące dane, jak zapisujesz fallbacki, czy też jak iterujesz po tablicach oraz jak budujesz obiekty.

Artykuł w skrócie

  • ?. optional chaining — eliminuje łańcuchy && i bezpiecznie zagłębia się w obiekty, zwracając undefined zamiast błędu
  • ?? nullish coalescing — lepszy fallback niż ||, bo respektuje 0 i '' jako poprawne wartości
  • Destructuring z domyślnymi wartościami — skraca wyciąganie danych z obiektów i tablic, czyniąc kod bardziej deklaratywnym
  • Array methods zamiast pętli — map, filter, reduce, find lepiej komunikują intencję niż imperatywne for
  • Logical assignment ||=, &&=, ??= — kondensuje wzorzec „przypisz jeśli brak wartości" do jednej linii
  • Czytelność ≠ krótszy kod — nowe syntaksy pomagają tylko gdy nie wymagają komentarza do zrozumienia

Nowoczesny JavaScript daje sporo konstrukcji, które skracają boilerplate i lepiej pokazują intencję, tyle że wiele projektów nadal pisze defensywny kod w stylu ES5, mimo że język od dawna oferuje prostsze i znacznie czytelniejsze idiomy.

W tym artykule zebrałem 10 technik, które realnie poprawiają czytelność kodu i nie chodzi tutaj o bycie sprytnym za wszelką cenę, lecz o to, żeby zapis był krótszy tam, gdzie ma to sens, i bardziej oczywisty dla osoby, która będzie go czytać kiedyś po Tobie.

Top tip

Najlepszy test czytelności jest prosty: jeśli nowa składnia skraca kod, ale wymaga zatrzymania się i odtworzenia logiki w głowie, to prawdopodobnie nie poprawia jakości. Używaj tych trików tam, gdzie intencja staje się bardziej oczywista.

1. Optional chaining — koniec z && && &&

Klasyczny problem: dostęp do zagnieżdżonych właściwości, które mogą nie istnieć.

Code
// ❌ Stary sposób jest brzydki i rozwlekły
const street = user && user.address && user.address.street
 
// ❌ Jeszcze gorszy sposób to
let street
if (user) {
  if (user.address) {
    street = user.address.street
  }
}
 
// ✅ Optional chaining — czysto i bezpiecznie
const street = user?.address?.street

Działa też z metodami oraz tablicami:

Code
// Metody
const result = api?.getData?.()
 
// Tablice
const firstItem = arr?.[0]
 
// Kombinacja
const city = users?.[0]?.address?.city

Jeśli którykolwiek element jest null lub undefined, wyrażenie zwraca undefined zamiast rzucać błąd i jest to świetny zamiennik dla defensywnego łańcucha sprawdzeń, tylko nie używaj go też bezrefleksyjnie: jeśli dana właściwość musi istnieć, ciche undefined może ukryć realny problem z danymi.

2. Nullish coalescing — lepszy fallback niż ||

Operator || ma problem: traktuje 0, '' i false jako falsy.

Code
// ❌ Problem z ||
const count = userCount || 10 // jeśli userCount = 0, dostaniesz 10!
const name = userName || 'Anonymous' // jeśli userName = '', dostaniesz 'Anonymous'
 
// ✅ Nullish coalescing — reaguje tylko na null/undefined
const count = userCount ?? 10 // jeśli userCount = 0, dostaniesz 0 ✓
const name = userName ?? 'Anonymous' // jeśli userName = '', dostaniesz '' ✓

Różnica jest subtelna, ale krytyczna:

  • || — fallback gdy wartość jest falsy (0, '', false, null, undefined)
  • ?? — fallback tylko gdy wartość jest null lub undefined

Najczęściej najlepiej działa to w parze z optional chaining:

Code
const city = user?.address?.city ?? 'Nieznane miasto'

3. Destructuring z domyślnymi wartościami

Destrukturyzacja szybko skraca kod, ale warto pamiętać o jednym szczególe, czyli że sama w sobie nie chroni przed null i undefined.

Code
// ❌ Ręczne sprawdzanie każdego pola osobno
const name = user.name === undefined ? 'Unknown' : user.name
const age = user.age === undefined ? 0 : user.age
const role = user.role === undefined ? 'user' : user.role
 
// ✅ Destructuring z defaults i bezpiecznym fallbackiem
const { name = 'Unknown', age = 0, role = 'user' } = user ?? {}
 
// ✅ W parametrach funkcji — jeszcze lepiej
function createUser({ name = 'Unknown', age = 0, role = 'user' } = {}) {
  return { name, age, role }
}
 
createUser({ name: 'Jan' }) // { name: 'Jan', age: 0, role: 'user' }
createUser() // { name: 'Unknown', age: 0, role: 'user' }

Zauważ = {} na końcu, które jest zabezpieczeniem na wypadek, gdy funkcja zostanie wywołana bez argumentów.

Ważny detal: default w destrukturyzacji działa tylko dla undefined, nie dla null. Jeśli chcesz fallback również dla null, użyj ?? albo zastosuj user ?? {} jak w przykładzie wyżej.

4. Object shorthand, czyli zdecydowanie mniej pisania

W sytuacji, kiedy nazwa zmiennej jest taka sama jak klucz obiektu:

Code
const name = 'Jan'
const age = 30
const city = 'Kraków'
 
// ❌ Powtórzenia
const user = {
  name: name,
  age: age,
  city: city,
}
 
// ✅ Shorthand
const user = { name, age, city }

Działa także z metodami:

Code
// ❌ Stary sposób
const calculator = {
  add: function (a, b) {
    return a + b
  },
}
 
// ✅ Shorthand methods
const calculator = {
  add(a, b) {
    return a + b
  },
}

To drobiazg, ale w return, payloadach API, czyli Application Programming Interface, definiuje sposób komunikacji między aplikacjami lub modułami. Tu chodzi o konwencje plików Next.js, które zamieniają eksportowaną funkcję w gotowy plik sitemap.xml lub robots.txt. i konfiguracjach ten zapis pojawia się cały czas, a im mniej mechanicznego powtarzania, tym łatwiej wyłapać naprawdę istotne fragmenty.

5. Spread operator do klonowania i łączenia

W większości codziennych przypadków spread jest najczytelniejszym sposobem na skopiowanie lub złożenie danych:

Code
// Klonowanie obiektów
const original = { a: 1, b: 2 }
const clone = { ...original }
 
// Łączenie obiektów (późniejsze nadpisują wcześniejsze)
const defaults = { theme: 'light', language: 'pl' }
const userSettings = { theme: 'dark' }
const settings = { ...defaults, ...userSettings }
// { theme: 'dark', language: 'pl' }
 
// Klonowanie tablic
const numbers = [1, 2, 3]
const copy = [...numbers]
 
// Łączenie tablic
const all = [...numbers, 4, 5, ...moreNumbers]

Uwaga, pamiętaj, że spread robi shallow copy, czyli kopiuje tylko pierwszy poziom:

Code
const user = {
  name: 'Jan',
  address: { city: 'Kraków' },
}
 
const copy = { ...user }
copy.address.city = 'Warszawa'
 
console.log(user.address.city) // 'Warszawa'

structuredClone() może pomóc przy głębszym kopiowaniu prostych struktur danych, ale nie jest uniwersalnym zamiennikiem dla każdego obiektu:

Code
const deep = structuredClone(complexObject)

Nie sklonujesz tak np. funkcji, a instancje własnych klas stracą swoje metody/prototypy.

6. Array methods zamiast pętli

Gdy transformujesz dane, metody tablicowe najczęściej (choć nie zawsze) lepiej pokazują intencję niż ręczna pętla:

Code
const users = [
  { name: 'Jan', age: 25, active: true },
  { name: 'Anna', age: 30, active: false },
  { name: 'Piotr', age: 35, active: true },
]
 
// ❌ Pętla for
const activeNames = []
for (let i = 0; i < users.length; i++) {
  if (users[i].active) {
    activeNames.push(users[i].name)
  }
}
 
// ✅ filter + map
const activeNames = users.filter((user) => user.active).map((user) => user.name)
// ['Jan', 'Piotr']

Inne przydatne metody:

Code
// find — pierwszy pasujący element
const jan = users.find((u) => u.name === 'Jan')
 
// some — czy którykolwiek spełnia warunek
const hasActive = users.some((u) => u.active) // true
 
// every — czy wszystkie spełniają warunek
const allActive = users.every((u) => u.active) // false
 
// reduce — agregacja
const totalAge = users.reduce((sum, u) => sum + u.age, 0) // 90

Nie traktuj tego jak dogmatu, ponieważ jeśli potrzebujesz break, continue, wielu efektów ubocznych albo sekwencyjnego await, zwykłe for...of często będzie czytelniejsze niż wciskanie wszystkiego na siłę w map() czy też reduce().

7. Template literals — koniec z konkatenacją

To jedna z tych zmian, które po prostu warto wprowadzić na stałe, ponieważ interpolacja stringów jest czytelniejsza niż +:

Code
const name = 'Jan'
const age = 30
 
// ❌ Konkatenacja
const message = 'Użytkownik ' + name + ' ma ' + age + ' lat.'
 
// ✅ Template literal
const message = `Użytkownik ${name} ma ${age} lat.`

W tym wypadku, prawdziwa moc to multiline strings i wyrażenia:

Code
// Multiline bez \n
const html = `
  <div class="card">
    <h2>${user.name}</h2>
    <p>${user.bio ?? 'Brak opisu'}</p>
  </div>
`
 
// Wyrażenia w środku
const status = `Status: ${isActive ? 'Aktywny' : 'Nieaktywny'}`
 
// Tagged templates (zaawansowane)
const query = sql`SELECT * FROM users WHERE id = ${userId}`

Najlepiej sprawdzają się w komunikatach, URL-ach, klasach CSS i prostych szablonach, a jeśli budujesz duże fragmenty HTML w aplikacji React, zwykle lepiej wejść poziom wyżej i renderować JSX zamiast składać stringi ręcznie.

8. Logical assignment operators

Nowe operatory przypisania z logiką warunkową:

Code
// ❌ Stary sposób
if (user.name == null) {
  user.name = 'Anonymous'
}
 
// ✅ Nullish assignment
user.name ??= 'Anonymous'
 
// ✅ Logical AND assignment
user.data &&= processData(user.data) // przetwarza TYLKO jeśli data istnieje
 
// ✅ Możesz też świadomie użyć ||=, jeśli pusty string/0/false mają być traktowane jako brak wartości
user.nickname ||= 'Anonymous'
 
// ✅ Kolejny przykład ??=
user.settings ??= getDefaultSettings() // przypisuje tylko jeśli null/undefined

Trzy operatory:

  • ||= — przypisz jeśli falsy ('', 0, false, null, undefined)
  • &&= — przypisz jeśli truthy
  • ??= — przypisz jeśli null/undefined

To bardzo wygodny zapis przy inicjalizacji danych i normalizacji payloadów, ale uważaj tylko tam, gdzie mutacja obiektu jest niepożądana, bo te operatory nadal modyfikują istniejącą referencję.

9. Object.entries/fromEntries — transformacja obiektów

Przekształcanie obiektów staje się wtedy banalnie proste:

Code
const prices = { apple: 2, banana: 1, orange: 3 }
 
// Obiekt → tablica par [klucz, wartość]
Object.entries(prices)
// [['apple', 2], ['banana', 1], ['orange', 3]]
 
// Tablica par → obiekt
Object.fromEntries([
  ['a', 1],
  ['b', 2],
])
// { a: 1, b: 2 }

Prawdziwa siła pojawia się wtedy, gdy połączysz je z metodami tablicowymi:

Code
// Podwój wszystkie ceny
const doublePrices = Object.fromEntries(
  Object.entries(prices).map(([key, value]) => [key, value * 2]),
)
// { apple: 4, banana: 2, orange: 6 }
 
// Filtruj obiekt
const expensive = Object.fromEntries(
  Object.entries(prices).filter(([_, value]) => value > 1),
)
// { apple: 2, orange: 3 }

10. Array.at() — negatywne indeksy

Dostęp do elementów od końca tablicy:

Code
const arr = [1, 2, 3, 4, 5]
 
// ❌ Stary sposób
const last = arr[arr.length - 1] // 5
const secondLast = arr[arr.length - 2] // 4
 
// ✅ Array.at() z negatywnym indeksem
const last = arr.at(-1) // 5
const secondLast = arr.at(-2) // 4

To drobnostka, ale poprawia czytelność wszędzie tam, gdzie często sięgasz po ostatni element: historii, breadcrumbsach, kolejkach czy wynikach sortowania i uwaga - działa też ze stringami:

Code
const str = 'Hello'
str.at(-1) // 'o'

Bonus: Object.groupBy() (ES2024)

Grupowanie elementów bez zewnętrznych bibliotek:

Code
const products = [
  { name: 'Apple', category: 'fruit' },
  { name: 'Banana', category: 'fruit' },
  { name: 'Carrot', category: 'vegetable' },
]
 
const grouped = Object.groupBy(products, (p) => p.category)
// {
//   fruit: [{ name: 'Apple', ... }, { name: 'Banana', ... }],
//   vegetable: [{ name: 'Carrot', ... }]
// }

To nowość ES2024, więc jeśli wspierasz starsze środowiska, sprawdź kompatybilność albo dodaj polyfill.

Nie chodzi o to, że reduce() nagle stał się złym rozwiązaniem, ale po prostu w wielu przypadkach Object.groupBy() mówi wprost, co robisz, więc wygrywa lepszą czytelnością.

Bonus: toSorted() zamiast mutowania tablicy

W komponentach React łatwo przypadkiem posortować tablicę pochodzącą z propsów albo stanu. sort() zmienia oryginał, natomiast toSorted() zwraca nową tablicę:

Code
const scores = [12, 4, 20]
const sorted = scores.toSorted((a, b) => a - b)
 
console.log(scores) // [12, 4, 20]
console.log(sorted) // [4, 12, 20]

To niewielka zmiana składni, ale lepiej komunikuje intencję: wynik ma być posortowaną kopią, a dane wejściowe pozostają bez zmian.

Werdykt Labu

Największą korzyścią z wymienionych wyżej technik nie jest to, że zapiszesz kilka linii mniej, ale rzecz w tym, że intencja staje się czytelna od razu: fallback jest fallbackiem, mapowanie jest mapowaniem, a odczyt z obiektu nie ginie pod warstwą boilerplate'u.

Jeśli masz zamiar wdrażać te sztuczki z głową, zacznij od ?., ?? i metod tablicowych, ponieważ właśnie one dają największy zwrot przy najmniejszym ryzyku. Potem dołóż destrukturyzację, Object.entries() i logical assignment operators tam, gdzie naprawdę upraszczają kod.

Najważniejszą z zasad jest, że krócej nie zawsze znaczy lepiej, ponieważ w sytuacji kiedy nowa składnia wymaga komentarza - by ją lepiej zrozumieć - prawdopodobnie nie poprawiła czytelności. Jeśli usuwa boilerplate i od razu pokazuje intencję, po prostu ją zostaw i nie kombinuj za bardzo. Szkoda czasu.


Chcesz pójść dalej? Sprawdź, kiedy async/await staje się pułapką wydajności.

  • 1. Optional chaining — koniec z && && &&1 min
  • 2. Nullish coalescing — lepszy fallback niż ||1 min
  • 3. Destructuring z domyślnymi wartościami1 min
  • 4. Object shorthand, czyli zdecydowanie mniej pisania1 min
  • 5. Spread operator do klonowania i łączenia1 min
  • 6. Array methods zamiast pętli1 min
  • 7. Template literals — koniec z konkatenacją1 min
  • 8. Logical assignment operators1 min
  • 9. Object.entries/fromEntries — transformacja obiektów1 min
  • 10. Array.at() — negatywne indeksy1 min
  • Bonus: Object.groupBy() (ES2024)1 min
  • Werdykt Labu1 min

Często zadawane pytania

Źródła i dokumentacjaZweryfikowano: 26 maja 2026

Materiały wykorzystane do weryfikacji artykułu „10 sztuczek w JavaScript, które sprawią, że Twój kod będzie 10x czytelniejszy”:

MDN: Optional chaining (?.), MDN: Nullish coalescing (??), MDN: Object.groupBy(), MDN: Array.prototype.toSorted(), MDN: Array.prototype.at().

Seria

JavaScript w praktyce
Część 1 / 2
  1. 10 sztuczek w JavaScript, które sprawią, że Twój kod będzie 10x czytelniejszy
  2. 2Async/await to pułapka — kiedy Promise.all() uratuje Twoją wydajność
Maciej Sala

O autorze

Maciej Sala

Maciej Sala — project manager i frontendowiec z doświadczeniem w marketingu internetowym. Na co dzień pracuję z Reactem, Next.js i TypeScriptem, łącząc perspektywę produktową z praktycznym podejściem do kodu. Przez kilka lat związany z branżą gier wideo jako project manager i game designer.

Absolwent historii na Uniwersytecie Jagiellońskim i studiów podyplomowych z marketingu internetowego na Akademii Górniczo-Hutniczej w Krakowie. Poza pracą trenuje na siłowni, maluje figurki i realizuje własne projekty.

Moje artykułyWięcej o mnie

Pomagam przekładać takie tematy na konkretne wdrożenia w frontendzie, SEO, analityce i procesie produktowym.

Skontaktuj się ze mną

Biblioteka wiedzy

Czytaj dalej

Zobacz więcej wpisów
TypeScript w React bez bólu — 7 wzorców, które realnie robią różnicę
TypeScript w React bez bólu — 7 wzorców, które realnie robią różnicę

TypeScript w React bez frustracji — ComponentProps, discriminated unions, polymorphic components, generic components, as prop, satisfies, stable types. 7 wzorców z produkcyjnych projektów.

Maciej Sala

Maciej Sala

Founder Strivelab

24 kwietnia 2026
Async/await to pułapka — kiedy Promise.all() uratuje Twoją wydajność
Async/await to pułapka — kiedy Promise.all() uratuje Twoją wydajność

Sekwencyjne await potrafią niepotrzebnie wydłużyć czas odpowiedzi aplikacji. Zobacz, kiedy użyć Promise.all(), kiedy Promise.allSettled(), a kiedy ograniczyć równoległość.

Maciej Sala

Maciej Sala

Founder Strivelab

2 listopada 2025
GEO — Generative Engine Optimization, czyli jak optymalizować treści pod AI
GEO — Generative Engine Optimization, czyli jak optymalizować treści pod AI

Czym jest GEO i jak zwiększyć szansę, że Twoje treści będą cytowane przez ChatGPT, Perplexity i Google AI Overviews? Praktyczny przewodnik dla developerów: treść, architektura, boty, schema, pomiar i realne ograniczenia.

Maciej Sala

Maciej Sala

Founder Strivelab

26 marca 2026
Poprzedni wpisWooCommerce od zera — konfiguracja sklepu, płatności i wysyłki krok po krokuJak skonfigurować WooCommerce od zera: produkty, płatności, wysyłka, podatki, REST API, HPOS i checklista przed startem sprzedaży.
Maciej Sala

Maciej Sala

Founder Strivelab

6 marca 2025
Następny wpisNext.js a SEO — kiedy naprawdę daje przewagę nad zwykłym ReactemJak Next.js wpływa na SEO w praktyce? SSR, SSG, metadata, Core Web Vitals i techniczne ograniczenia, o których warto wiedzieć przed wyborem frameworka.
Maciej Sala

Maciej Sala

Founder Strivelab

15 lipca 2025