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 (aje v frozen objektu)obj.azůstává1obj.nested.b = 20- FUNGUJE! (nested objekt NENÍ frozen)obj.nested.bse změní na20- 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 →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
- 05.1 Vytvoření objektu
- 05.2 Vlastnosti
- 05.3 Metody objektu
- 05.4 This keyword
- 05.5 Destructuring objektů
- 05.6 Spread u objektů
- 05.7 Optional chaining
- 05.8 Nullish coalescing
- 05.9 Object.keys/values/entries
- 05.10 Computed properties
- 05.11 Getters a setters
- 05.12 Object.freeze/seal
Struktura lekcí (souborový strom)
- 1.1 Úvod do JavaScriptu a TypeScriptu
- 1.2 Nastavení prostředí
- 1.3 První program
- 1.4 Proměnné: var, let, const
- 1.5 Datové typy - přehled
- 1.6 String (řetězce)
- 1.7 Number (čísla)
- 1.8 Boolean (pravda/nepravda)
- 1.9 Null a Undefined
- 1.10 Type Inference vs Annotations
- 1.11 Aritmetické operátory
- 1.12 Porovnávací operátory
- 1.13 Logické operátory
- 1.14 Komentáře
- 1.15 Console metody
- 03.01 Deklarace funkce
- 03.02 Function Expression
- 03.03 Arrow Functions
- 03.04 Parametry a argumenty
- 03.05 Return hodnoty
- 03.06 Výchozí parametry
- 03.07 Rest parametry
- 03.08 Co je Scope
- 03.09 Lexikální Scope
- 03.10 Řetězec Scope
- 03.11 Globální Scope
- 03.12 Životní Cyklus Proměnných
- 03.13 Omezení Scope
- 03.14 Použití Closures
- 03.15 Callback funkce
- 03.16 Higher-order Functions
- 03.17 IIFE
- 03.18 Void funkce
- 03.19 Rekurze
- v přípravě
- v přípravě
- v přípravě
- v přípravě
- 01 — Co je Next.js
- 02 — Vytvoření projektu
- 03 — Struktura projektu (app/)
- 04 — Page komponenty (page.js / page.tsx)
- 05 — Layout komponenty (layout.js / layout.tsx)
- 06 — File-based routing
- 07 — Dynamické routy ([id]/page.js)
- 08 — Link komponenta (navigace)
- 09 — Image komponenta (next/image)
- 10 — Metadata (title, description, Open Graph)
- 11 — Loading UI (loading.js / loading.tsx)
- 12 — Error handling (error.js / error.tsx)
- 13 — Not Found (not-found.js / not-found.tsx)
- v přípravě
- v přípravě
- v přípravě