Początkujący
+25 XP

👋 Zacznij uczyć się JavaScript już teraz — za darmo!

📖

Typ object — niuanse i pułapki

Dlaczego null jest obiektem, tablice są obiektami i jak nie zepsuć kodu przy kopiowaniu

🎒

Object — plecak z podpisanymi kieszeniami

Prymityw (liczba, string) to jedna prosta rzecz: moneta, klucz. Obiekt to plecak z nazwanymi kieszeniami. Kieszeń 'imie' → 'Jan', kieszeń 'wiek' → 25. W środku mogą być inne plecaki. To główna cecha — obiekt przechowuje USTRUKTURYZOWANE dane z nazwanymi polami.

Czym naprawdę jest obiekt

Obiekt to zbiór par klucz: wartość. Klucze to stringi (lub Symbol), wartości mogą być dowolnego typu.

js
const uzytkownik = {
  imie: "Jan",          // klucz: 'imie', wartość: string
  wiek: 25,             // klucz: 'wiek', wartość: number
  jestStudentem: true,  // klucz: 'jestStudentem', wartość: boolean
  adres: {              // klucz: 'adres', wartość: kolejny obiekt!
    miasto: "Warszawa",
    kod: "00-001",
  },
};

// Dostęp do właściwości
console.log(uzytkownik.imie);          // "Jan" — notacja z kropką
console.log(uzytkownik["imie"]);       // "Jan" — notacja z nawiasem
console.log(uzytkownik.adres.miasto);  // "Warszawa" — zagnieżdżony dostęp

Pułapka #1: typeof null === "object"

To jeden z najsłynniejszych błędów JavaScript:

js
console.log(typeof null);    // "object" ← BŁĄD W SAMYM JS
console.log(typeof {});      // "object" — to poprawne
console.log(typeof []);      // "object" — tablice to też object!

typeof null === "object" — to błąd z 1995 roku (pierwszy tydzień istnienia JavaScript). Null nie jest obiektem, ale nie można tego naprawić: zbyt dużo starego kodu na tym polega.

Jak poprawnie sprawdzać null:

js
// ŹLE:
if (typeof value === "object") { ... } // łapie też null!

// DOBRZE:
if (value !== null && typeof value === "object") { ... }

Pułapka #2: Tablice to też object

js
let owoce = ["jabłko", "banan"];

console.log(typeof owoce);          // "object" — nie "array"!
console.log(Array.isArray(owoce));  // true — poprawne sprawdzenie
console.log(Array.isArray({}));     // false

// Dlaczego? Tablica w JS to obiekt ze specjalnymi kluczami numerycznymi:
let tab = ["a", "b", "c"];
// Właściwie: { 0: "a", 1: "b", 2: "c", length: 3 }
console.log(tab[0]);      // "a"
console.log(tab.length);  // 3

Zasada: do sprawdzenia czy coś jest tablicą — zawsze używaj Array.isArray(value), nie typeof.

Pułapka #3: Typ prymitywny vs typ referencyjny

To NAJWAŻNIEJSZA pułapka obiektów. Prymitywy przechowują wartości, obiekty przechowują referencje do miejsca w pamięci.

js
// Prymitywy — kopiowane przez wartość
let a = 5;
let b = a;   // b dostaje KOPIĘ wartości 5
b = 10;
console.log(a); // 5 — a NIE zmieniło się!

// Obiekty — kopiowane przez referencję
let user1 = { imie: "Jan" };
let user2 = user1;   // user2 wskazuje na TEN SAM obiekt!
user2.imie = "Maria";
console.log(user1.imie); // "Maria" — user1 TEŻ się zmienił!

user2 = user1 nie kopiuje obiektu — tylko przekazuje adres w pamięci. Obie zmienne wskazują na to samo miejsce.

javascript
💬

{ ...oryginal } — operator spread. Kopiuje WSZYSTKIE właściwości do nowego obiektu. To 'płytka kopia'.

Pułapka #4: Obiekty porównywane przez referencję

js
// Prymitywy porównywane przez WARTOŚĆ
console.log(5 === 5);           // true — te same wartości
console.log("JS" === "JS");     // true

// Obiekty porównywane przez REFERENCJĘ (adres w pamięci)
console.log({} === {});         // false — różne obiekty!
console.log([] === []);         // false — różne tablice!

let a = { x: 1 };
let b = a;          // b wskazuje na TEN SAM obiekt
console.log(a === b); // true — ten sam adres!

{} === {}false, bo to dwa różne obiekty w różnych miejscach pamięci, nawet jeśli wyglądają identycznie.

Jak porównać zawartość? Zamień na string: JSON.stringify(obj1) === JSON.stringify(obj2)

Pułapka #5: Płytka kopia vs głęboka kopia

js
// Płytka kopia — spread
let uzytkownik = { imie: "Jan", adres: { miasto: "Warszawa" } };
let kopia = { ...uzytkownik };

kopia.imie = "Maria";          // OK — prymityw był skopiowany
kopia.adres.miasto = "Kraków"; // NIEBEZPIECZNE!

console.log(uzytkownik.imie);          // "Jan" — bez zmian ✓
console.log(uzytkownik.adres.miasto);  // "Kraków" — ZMIENIONY! ✗
// Spread kopiuje tylko pierwszy poziom!

// Głęboka kopia — przez JSON
let kopiaGleboka = JSON.parse(JSON.stringify(uzytkownik));
kopiaGleboka.adres.miasto = "Gdańsk";
console.log(uzytkownik.adres.miasto);  // "Kraków" — bez zmian ✓

Spread ({...obj}) — płytka kopia. Dla zagnieżdżonych obiektów — użyj JSON.parse(JSON.stringify(obj)) lub structuredClone(obj) (nowoczesna metoda).

Dwa najczęstsze błędy z obiektami: 1. let kopia = obj — myślisz że skopiowałeś, ale obie zmienne wskazują na ten sam obiekt. 2. typeof null === 'object' — sprawdzasz typ i zapominasz wykluczyć null. Zapamiętaj: do kopiowania — spread {...obj}, do sprawdzenia null — value !== null.

javascript
💬

structuredClone() — wbudowana funkcja do głębokiego kopiowania. Obsługiwana przez wszystkie nowoczesne przeglądarki.

Komentarze

Zaloguj się lub Zacznij aby zostawić komentarz.