Domů O mně Služby Portfolio Učím Blog Kontakt
← Zpět na učím

05.12 Object.freeze/seal

Výuka

Proč immutability?

Object.freeze() a Object.seal() jsou metody pro zamrznutí objektů - zabraňují změnám vlastností. Vytváří immutabilní (neměnné) objekty.

Proč to potřebujeme?

  • Prevence mutací - Zabraň náhodným změnám objektu
  • Immutability - Funkční programování a React/Redux patterns
  • Konstanty - Zajisti, že konfigurace se nezmění
  • Thread-safety - Bezpečné sdílení objektů

Představ si to jako: Lamina dokument. Object.freeze() je jako zalaminování - nemůžeš přidávat, odstraňovat ani měnit text. Object.seal() je jako pevná vazba - nemůžeš přidávat/odstraňovat stránky, ale můžeš na nich psát.

Jak to funguje?

Object metody pro immutability:
1. Object.freeze(obj) - zmrazí objekt (nelze add/delete/modify)
2. Object.seal(obj) - zapečetí objekt (nelze add/delete, ale lze modify)
3. Object.preventExtensions(obj) - nelze add (lze delete/modify)
4. Object.isFrozen(obj) - kontrola, zda je zmražený
5. Object.isSealed(obj) - kontrola, zda je zapečetěný

Klíčové koncepty

  • Object.freeze() - plně neměnný objekt
  • Object.seal() - nelze přidávat/odstraňovat, lze měnit hodnoty
  • Object.preventExtensions() - nelze přidávat nové vlastnosti
  • Shallow freeze - zmrazí jen první úroveň (ne vnořené objekty!)
  • Deep freeze - rekurzivně zmrazí i vnořené objekty
  • Strict mode - operace vyhodí error místo ignorování

JavaScript

Příklad 1: Object.freeze() - plně neměnný objekt

const config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
  retries: 3
};

// Zamraž objekt
Object.freeze(config);

// Pokus o změnu hodnoty - ignoruje se
config.timeout = 10000;
console.log(config.timeout);
// → 5000 (nezměnilo se!)

// Pokus o přidání vlastnosti - ignoruje se
config.newProp = 'value';
console.log(config.newProp);
// → undefined (nepřidalo se!)

// Pokus o odstranění vlastnosti - ignoruje se
delete config.retries;
console.log(config.retries);
// → 3 (neodstranilo se!)

// V strict mode by všechny pokusy vyhodily TypeError
'use strict';
// config.timeout = 10000;  // TypeError: Cannot assign to read only property

Co se stalo?

  • Object.freeze(obj) - zamrazí objekt
  • Nelze: přidávat, odstraňovat, měnit vlastnosti
  • Non-strict mode: operace se ignorují (tiché selhání)
  • Strict mode: operace vyhodí TypeError

Příklad 2: Object.seal() - zapečetěný objekt

const user = {
  name: 'Alice',
  age: 25,
  city: 'Praha'
};

// Zapečeť objekt
Object.seal(user);

// ✅ Můžeš MĚNIT hodnoty existujících vlastností
user.age = 26;
console.log(user.age);
// → 26 (změnilo se!)

user.city = 'Brno';
console.log(user.city);
// → Brno (změnilo se!)

// ❌ Nemůžeš PŘIDÁVAT nové vlastnosti
user.email = 'alice@example.com';
console.log(user.email);
// → undefined (nepřidalo se!)

// ❌ Nemůžeš ODSTRAŇOVAT vlastnosti
delete user.city;
console.log(user.city);
// → Brno (neodstranilo se!)

Co se stalo?

  • Object.seal(obj) - zapečetí objekt
  • Lze: měnit hodnoty existujících vlastností
  • Nelze: přidávat nebo odstraňovat vlastnosti
  • Užitečné pro fixed structure s měnitelnými hodnotami

Příklad 3: Object.preventExtensions() - nelze rozšiřovat

const product = {
  name: 'Laptop',
  price: 25000
};

// Zabraň rozšiřování
Object.preventExtensions(product);

// ✅ Můžeš MĚNIT hodnoty
product.price = 24000;
console.log(product.price);
// → 24000 (změnilo se!)

// ✅ Můžeš ODSTRAŇOVAT vlastnosti
delete product.price;
console.log(product.price);
// → undefined (odstranil o se!)

// ❌ Nemůžeš PŘIDÁVAT nové vlastnosti
product.stock = 10;
console.log(product.stock);
// → undefined (nepřidalo se!)

Co se stalo?

  • Object.preventExtensions(obj) - zabraň přidávání vlastností
  • Lze: měnit hodnoty, odstraňovat vlastnosti
  • Nelze: přidávat nové vlastnosti
  • Nejslabší z těchto tří metod

Příklad 4: Kontrola stavu objektu

const obj1 = { a: 1 };
const obj2 = { b: 2 };
const obj3 = { c: 3 };

Object.freeze(obj1);
Object.seal(obj2);
Object.preventExtensions(obj3);

// Kontrola frozen
console.log(Object.isFrozen(obj1));  // → true
console.log(Object.isFrozen(obj2));  // → false (seal !== freeze)
console.log(Object.isFrozen(obj3));  // → false

// Kontrola sealed
console.log(Object.isSealed(obj1));  // → true (freeze → sealed too)
console.log(Object.isSealed(obj2));  // → true
console.log(Object.isSealed(obj3));  // → false

// Kontrola extensible
console.log(Object.isExtensible(obj1));  // → false (frozen)
console.log(Object.isExtensible(obj2));  // → false (sealed)
console.log(Object.isExtensible(obj3));  // → false
console.log(Object.isExtensible({}));    // → true (normální objekt)

Co se stalo?

  • Object.isFrozen() - kontrola, zda je zmražený
  • Object.isSealed() - kontrola, zda je zapečetěný
  • Object.isExtensible() - kontrola, zda je rozšiřitelný
  • Frozen → Sealed - zmražený objekt je zároveň zapečetěný

Příklad 5: Shallow freeze - POZOR u vnořených objektů!

const user = {
  name: 'Bob',
  age: 30,
  address: {
    city: 'Praha',
    zip: '11000'
  }
};

// Zmraž objekt
Object.freeze(user);

// ❌ Nemůžeš změnit top-level vlastnost
user.name = 'Charlie';
console.log(user.name);
// → Bob (nezměnilo se)

// ⚠️ POZOR: Můžeš změnit VNOŘENÝ objekt!
user.address.city = 'Brno';
console.log(user.address.city);
// → Brno (ZMĚNILO SE!)

// Důvod: freeze je SHALLOW (povrchní)
console.log(Object.isFrozen(user));          // → true
console.log(Object.isFrozen(user.address));  // → false (vnořený objekt NENÍ frozen!)

Co se stalo?

  • Shallow freeze - zmrazí jen první úroveň
  • Vnořené objekty NEJSOU zmražené!
  • Musíš ručně zmrazit každou úroveň

Příklad 6: Deep freeze - rekurzivní zmrazení

// Utility funkce pro deep freeze
function deepFreeze(obj) {
  // Zmraz sám objekt
  Object.freeze(obj);

  // Rekurzivně zmraz všechny vlastnosti, které jsou objekty
  Object.values(obj).forEach(value => {
    if (typeof value === 'object' && value !== null) {
      deepFreeze(value);
    }
  });

  return obj;
}

const user = {
  name: 'David',
  age: 35,
  address: {
    city: 'Ostrava',
    zip: '70200',
    coords: {
      lat: 49.8,
      lng: 18.3
    }
  }
};

// Deep freeze
deepFreeze(user);

// ❌ Nemůžeš změnit top-level
user.name = 'Eve';
console.log(user.name);
// → David (nezměnilo se)

// ❌ Nemůžeš změnit vnořený objekt
user.address.city = 'Praha';
console.log(user.address.city);
// → Ostrava (nezměnilo se!)

// ❌ Ani hluboce vnořený objekt
user.address.coords.lat = 50;
console.log(user.address.coords.lat);
// → 49.8 (nezměnilo se!)

// Všechny úrovně jsou frozen
console.log(Object.isFrozen(user));                // → true
console.log(Object.isFrozen(user.address));        // → true
console.log(Object.isFrozen(user.address.coords)); // → true

Co se stalo?

  • Deep freeze - rekurzivně zmrazí všechny úrovně
  • Žádné vnořené objekty nelze měnit
  • Užitečné pro true immutability

TypeScript

TypeScript přidává readonly modifikátor a Readonly<T> utility typ.

Stejné příklady s typy

// Readonly properties v interface
interface Config {
  readonly apiUrl: string;
  readonly timeout: number;
  retries: number;
}

const config: Config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
  retries: 3
};

config.retries = 5;  // ✅ OK
// config.timeout = 10000;  // ❌ Error: Cannot assign to 'timeout' because it is a read-only property

// Readonly<T> utility type
type ReadonlyConfig = Readonly<Config>;

const config2: ReadonlyConfig = {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
  retries: 3
};

// config2.retries = 5;  // ❌ Error: všechny vlastnosti jsou readonly

// Object.freeze s typy
const obj = Object.freeze({
  name: 'Alice',
  age: 25
});

// obj.age = 26;  // ❌ Error: Cannot assign to 'age' because it is a read-only property

// Deep readonly
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

interface User {
  name: string;
  address: {
    city: string;
    zip: string;
  };
}

const user: DeepReadonly<User> = {
  name: 'Bob',
  address: {
    city: 'Praha',
    zip: '11000'
  }
};

// user.name = 'Charlie';  // ❌ Error
// user.address.city = 'Brno';  // ❌ Error (deep readonly!)

// as const assertion - deep readonly literal
const config3 = {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
  nested: {
    value: 10
  }
} as const;

// config3.timeout = 10000;  // ❌ Error
// config3.nested.value = 20;  // ❌ Error (deep!)

TypeScript přidává:

  • readonly modifikátor - compile-time ochrana
  • Readonly<T> - utility type pro všechny vlastnosti
  • DeepReadonly<T> - custom type pro deep readonly
  • as const - deep readonly literal
  • Prevenci chyb - compile-time kontrola

Rozdíl JS vs TS

JavaScript:

  • freeze/seal - runtime ochrana
  • Shallow freeze (jen první úroveň)
  • Chyby v strict mode, ignorování v non-strict

TypeScript:

  • readonly - compile-time ochrana
  • DeepReadonly možné přes custom type
  • Prevence před kompilací
// JavaScript - runtime check
const obj = Object.freeze({ a: 1 });
obj.a = 2;  // Ignoruje se (nebo error ve strict mode)

// TypeScript - compile-time check
const obj: Readonly<{ a: number }> = { a: 1 };
// obj.a = 2;  // ❌ Error: Cannot assign (před spuštěním!)

Tip

💡 Používej Object.freeze() pro konstanty:

// ✅ Zamraž konfiguraci
const CONFIG = Object.freeze({
  API_URL: 'https://api.example.com',
  TIMEOUT: 5000,
  MAX_RETRIES: 3
});

// Nemůžeš omylem změnit
// CONFIG.TIMEOUT = 10000;  // Ignoruje se

💡 Deep freeze pro vnořené objekty:

// ❌ Shallow freeze - vnořené objekty lze měnit
const obj = Object.freeze({
  nested: { value: 10 }
});
obj.nested.value = 20;  // Změní se!

// ✅ Deep freeze
function deepFreeze(obj) {
  Object.freeze(obj);
  Object.values(obj).forEach(v => {
    if (typeof v === 'object' && v !== null) deepFreeze(v);
  });
  return obj;
}

💡 V TypeScript preferuj as const:

// ✅ Deep readonly literal
const config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
  nested: { value: 10 }
} as const;

// Všechny vlastnosti jsou readonly (i vnořené!)

Kvíz

Co vypíše tento kód?

const obj = {
  a: 1,
  nested: { b: 2 }
};

Object.freeze(obj);
obj.a = 10;
obj.nested.b = 20;

console.log(obj.a);
console.log(obj.nested.b);

- obj.a je frozen, nemůže se změnit

- obj.nested.b není frozen, může se změnit

- - Object.freeze(obj) - zmrazí objekt (shallow!)

  • obj.a = 10 - IGNORUJE SE (a je v frozen objektu)
  • obj.a zůstává 1
  • obj.nested.b = 20 - FUNGUJE! (nested objekt NENÍ frozen)
  • obj.nested.b se změní na 20
  • Freeze je SHALLOW - zmrazí jen první úroveň!

- obj.a je frozen

Důležité: Object.freeze() je SHALLOW - zmrazí jen první úroveň, ne vnořené objekty!

Důležité: Object.freeze() je SHALLOW - zmrazí jen první úroveň, ne vnořené objekty!

🎯 Závěrečný projekt

Po dokončení všech 8 dílů vytvoříte jednoduchou Todо aplikaci v čistém JavaScriptu. Naučíte se, jak aplikovat vše, co jste se naučili, na reálný projekt.

Zobrazit podrobnosti projektu →

Připraveni začít?

Zaregistrujte se a získejte přístup ke všem dílům tohoto seriálu

Kontaktujte mě

Informace o seriálu

Obtížnost

Délka

Cca 480 minut

Počet videí

8 videí + projekty

Certifikát

Po dokončení obdržíte certifikát


Lekce v této sekci


Struktura lekcí (souborový strom)

06. Typescript specifika
  • v přípravě
08. Moduly tridy
  • v přípravě
09. React zaklady
  • v přípravě
10. React hooks
  • v přípravě
12. Nextjs server
  • v přípravě
13. Databaze auth
  • v přípravě
14. Nextjs pokrocile
  • v přípravě