Object.freeze / Object.seal
Object.freeze va Object.seal farqi, property descriptor darajasida (writable, configurable, extensible) nima o'zgarishi, shallow freeze muammosi va deep freeze yechimi, const bilan farqi, strict mode'dagi sokin muvaffaqiyatsizlik xavfi, va konstanta/enum/state immutability uchun amaliy qo'llanilishi.
100-dars
Object.freeze / Object.seal
Tasavvur qiling, siz bir varaq qog'ozga biror narsa yozdingiz. Endi uni laminatsiya qildingiz — endi hech kim unga yozib, o'chirib bo'lmaydi, u abadiy shu holatda qoladi.
Object.freeze() — aynan shu: obyektni "laminatsiya qiladi", uni butunlay o'zgarmas (immutable) qiladi.
Object.seal() — biroz yumshoqroq: qog'ozga yozganingizni o'chirib, ustidan qayta yozish mumkin, lekin yangi qator qo'shib bo'lmaydi.
1. Kod bilan — asosiy farq
const obj = { name: 'Ali', age: 25 };
// FREEZE — hech narsa o'zgarmaydi
const frozen = Object.freeze(obj);
frozen.age = 30; // e'tiborga olinmaydi (yoki strict mode'da xato)
frozen.city = 'Toshkent'; // qo'shilmaydi
delete frozen.name; // o'chirilmaydi
console.log(frozen); // { name: 'Ali', age: 25 } — HECH NARSA o'zgarmadi
// SEAL — mavjudni o'zgartirish mumkin, lekin qo'shish/o'chirish yo'q
const sealed = Object.seal(obj);
sealed.age = 30; // ISHLAYDI — mavjud propertyni o'zgartirish mumkin
sealed.city = 'Toshkent'; // e'tiborga olinmaydi — yangi qo'shib bo'lmaydi
delete sealed.name; // ishlamaydi — o'chirib bo'lmaydi
console.log(sealed); // { name: 'Ali', age: 30 } — FAQAT age o'zgardi
Nega bu farq muhim — jadval bilan aniqlashtiramiz
| Amal | Oddiy obyekt | Object.seal() |
Object.freeze() |
|---|---|---|---|
| Mavjud qiymatni o'zgartirish | ✅ | ✅ | ❌ |
| Yangi property qo'shish | ✅ | ❌ | ❌ |
| Propertyni o'chirish | ✅ | ❌ | ❌ |
| Property tartibini/konfiguratsiyasini o'zgartirish | ✅ | ❌ | ❌ |
Eslash uchun oddiy qoida: seal — "qopqoqni yopdim, ichiga narsa qo'sha olmaysiz, chiqara olmaysiz, lekin ichidagini aralashtirib turaverasiz". freeze — "hammasi muzlab qoldi, hech narsaga tegib bo'lmaydi".
2. Property descriptor darajasida — nima aslida o'zgaryapti
Property descriptor mavzusini eslang (writable, configurable, enumerable). freeze/seal — aynan shu descriptorlarni o'zgartiradi:
const obj = { x: 1 };
console.log(Object.getOwnPropertyDescriptor(obj, 'x'));
// { value: 1, writable: true, enumerable: true, configurable: true }
Object.seal(obj);
console.log(Object.getOwnPropertyDescriptor(obj, 'x'));
// { value: 1, writable: true, enumerable: true, configurable: false }
// ↑ FAQAT shu o'zgardi
Object.freeze(obj);
console.log(Object.getOwnPropertyDescriptor(obj, 'x'));
// { value: 1, writable: false, enumerable: true, configurable: false }
// ↑ ENDI bu ham o'zgardi
Aniq nima sodir bo'lyapti:
Object.seal()— har bir property'ningconfigurable: falseqiladi (property'ni o'chirish yoki qayta konfiguratsiya qilish taqiqlanadi), va butun obyektniextensible: falseqiladi (yangi property qo'shib bo'lmaydi). Lekinwritable— tegilmaydi, shuning uchun mavjud qiymatni yozish mumkin.Object.freeze()—seal()qilgan hamma narsani qiladi, qo'shimcha har bir property'ningwritable: falseqiladi.
Ya'ni freeze = seal + writable: false — matematik jihatdan aytganda, freeze — sealning qattiqroq versiyasi.
3. Eng ko'p tushinilmaydigan joy — shallow (yuzaki) ekanligi
Bu — amalda eng ko'p xato qilinadigan joy:
const user = Object.freeze({
name: 'Ali',
address: { city: 'Toshkent', zip: '100000' }
});
user.name = 'Vali'; // ishlamaydi — to'g'ri
user.address.city = 'Samarqand'; // BU ISHLAYDI!
console.log(user.address.city); // "Samarqand" — o'zgardi!
Nega bu sodir bo'ladi? Object.freeze() — faqat birinchi daraja property'larni muzlatadi. user.address — bu o'zi bir obyekt, va u frozen emas, faqat user.addressning o'zi (ya'ni "qaysi obyektga ishora qilishi") o'zgartirib bo'lmaydi:
user.address = {}; // BU ISHLAMAYDI — user.address'ning o'zini almashtirib bo'lmaydi
user.address.city = 'x'; // BU ISHLAYDI — chunki address obyektining ICHKI qismi frozen emas
Bu — xuddi Primitive vs Non-primitive, reference vs value mavzusiga to'g'ridan-to'g'ri bog'liq: user.address — bu pointer (referens), va freeze faqat "bu pointerni o'zgartirib bo'lmaydi" deydi, lekin pointer ko'rsatib turgan obyektning ichini himoya qilmaydi.
Yechim — Deep freeze (o'zingiz yozish kerak)
function deepFreeze(obj) {
Object.getOwnPropertyNames(obj).forEach(key => {
const value = obj[key];
if (value && typeof value === 'object' && !Object.isFrozen(value)) {
deepFreeze(value); // REKURSIV — har bir ichki obyektga ham qo'llaniladi
}
});
return Object.freeze(obj);
}
const user = deepFreeze({
name: 'Ali',
address: { city: 'Toshkent' }
});
user.address.city = 'Samarqand'; // ENDI ishlamaydi
console.log(user.address.city); // "Toshkent"
Diqqat: JavaScript'ning o'zida built-in deepFreeze yo'q — bu har doim qo'lda yoziladigan yoki kutubxonadan (masalan, deep-freeze npm paketi) olinadigan funksiya.
4. Tekshirish funksiyalari
Object.isFrozen(obj); // true/false
Object.isSealed(obj); // true/false
Object.isExtensible(obj); // yangi property qo'shish mumkinmi
Muhim mantiqiy bog'liqlik: agar Object.isFrozen(obj) === true, demak avtomatik ravishda Object.isSealed(obj) === true ham to'g'ri (chunki freeze — sealning "kattarog'i"), lekin teskarisi to'g'ri emas.
5. const bilan farqi — bu ham ko'p aralashtiriladi
const obj = { count: 0 };
obj.count = 5; // BU ISHLAYDI! const'ga zid emas
console.log(obj.count); // 5
Nega? const — faqat o'zgaruvchining o'zi qayta belgilanishini (obj = {...}) taqiqlaydi, obyekt ichidagi narsani o'zgartirishga hech qanday aloqasi yo'q. const — bu "pointer" darajasidagi cheklov, freeze — "obyekt ichi" darajasidagi cheklov. Ular — butunlay boshqa narsalarni himoya qiladi:
const obj = Object.freeze({ count: 0 });
obj = { count: 1 }; // XATO — const qoidasi buzildi
obj.count = 1; // E'tiborga olinmaydi — freeze qoidasi (xato tashlamaydi, sokin)
6. Strict mode'dagi farq — sokin muvaffaqiyatsizlik muammosi
Bu — xavfli joy, ko'p dasturchi bilmaydi:
'use strict';
const frozen = Object.freeze({ x: 1 });
frozen.x = 2; // TypeError: Cannot assign to read only property 'x'
// strict mode'siz (oddiy script yoki modul bo'lmagan fayl):
const frozen = Object.freeze({ x: 1 });
frozen.x = 2; // HECH QANDAY XATO! Sokin ravishda e'tiborga olinmaydi
console.log(frozen.x); // 1 — o'zgarmadi, lekin ogohlantirish ham yo'q
Amaliy xulosa: ES Modules (import/export ishlatuvchi fayllar) va classlar avtomatik strict mode'da ishlaydi, shuning uchun zamonaviy loyihalarda bu muammo kamroq uchraydi. Lekin eski, oddiy <script> fayllarida — freezeni buzishga urinish hech qanday xato bermay, sokin muvaffaqiyatsiz bo'lishi mumkin, bu esa xatoni sezmasdan qolish xavfini beradi.
7. Amaliy qo'llanilish — nega kerak
a) Konstantalarni himoya qilish
const CONFIG = Object.freeze({
API_URL: 'https://api.example.com',
MAX_RETRIES: 3
});
// Endi kodning istalgan joyida, tasodifan CONFIG.MAX_RETRIES = 100 deb
// yozib qo'yilsa ham — bu e'tiborga olinmaydi, xato oldini oladi
b) Redux/State management'da immutability
function reducer(state, action) {
// state'ni TO'G'RIDAN-TO'G'RI o'zgartirish o'rniga:
// state.count++; // XATO YONDASHUV
// Yangi obyekt qaytariladi:
return { ...state, count: state.count + 1 };
}
Bu yerda Object.freeze(state) — development paytida himoya sifatida ishlatiladi: agar kimdir xato qilib, state.count++ deb yozib qo'ysa, freeze bu urinishni bloklaydi, xato darhol ko'rinadi (development'da, strict mode bilan), production'da esa jim o'tib ketmaydi.
c) Enum-ga o'xshash struktura yaratish
const Status = Object.freeze({
PENDING: 'pending',
ACTIVE: 'active',
DONE: 'done'
});
// Status.PENDING = 'boshqa' — bu urinish bloklanadi, doimiylik kafolatlanadi