Symbol — nima va qachon kerak

~15 daq · JavaScript · Ilg'or mavzular

Muammodan boshlaylik

Siz katta kutubxona yozdingiz. Foydalanuvchilar uni o'z ob'ektlarida ishlatadi. Kutubxona ob'ektga id xususiyat qo'shishi kerak — ichki maqsad uchun.

Muammo: foydalanuvchining ob'ektida allaqachon id bo'lishi mumkin. Siz id qo'shsangiz — uning qiymatini yozib tashlaysiz.

// Foydalanuvchining ob'ekti
const mahsulot = { id: 42, nomi: "Noutbuk", narx: 8000000 };

// Kutubxona ichki id qo'shmoqchi
mahsulot.id = "ichki-001"; // ❌ — foydalanuvchining id si yo'qoldi!

Symbol — bu muammoni hal qiladi: kalit nom to'qnashuvlari bo'lmaydi.


Symbol nima?

Symbol — yagona va takrorlanmas qiymat. Har yangi Symbol — dunyoda yagona. Hatto bir xil tavsif bilan yaratilsa ham — ular teng emas.

Hayotiy o'xshatma

Pul birliklarini tasavvur qiling. 100 so'mlik ikki tanga — ko'rinishi bir xil, raqami bir xil. Lekin ular ikki alohida tanga — bir xil emas. Symbol ham shunday: tavsifi bir xil bo'lsa ham — har biri yagona.

const a = Symbol("id");
const b = Symbol("id");

console.log(a === b); // false ← bir xil tavsif, lekin turli Symbol
console.log(typeof a); // "symbol"
console.log(a.toString()); // "Symbol(id)"
console.log(a.description); // "id" ← tavsif

Symbol kalit sifatida

Symbol ning asosiy kuchi — ob'ekt xususiyati kalit sifatida ishlatish. Symbol kalit — oddiy matn kalit bilan to'qnashmaydi.

const ICHKI_ID = Symbol("id"); // ← kutubxona yaratdi

const mahsulot = {
  id: 42,                        // ← foydalanuvchining id si
  nomi: "Noutbuk",
  [ICHKI_ID]: "ichki-001",       // ← kutubxonaning ichki id si
};

console.log(mahsulot.id);        // 42 ← o'zgarmadi ✅
console.log(mahsulot[ICHKI_ID]); // "ichki-001" ✅

To'qnashuv yo'q — chunki Symbol yagona. Hech kim sizning ICHKI_ID Symbol ini qaytadan yaratolmaydi.


Symbol lar ko'rinmaydi — "yashirin" xususiyatlar

Symbol xususiyatlar oddiy ko'rishda chiqmaydi:

const ID = Symbol("id");
const ob = { ism: "Jasur", [ID]: 42 };

// Oddiy usullar Symbol ni ko'rmaydi
console.log(Object.keys(ob));      // ["ism"] ← ID yo'q
console.log(Object.values(ob));    // ["Jasur"] ← 42 yo'q
console.log(JSON.stringify(ob));   // '{"ism":"Jasur"}' ← ID yo'q

for (const kalit in ob) {
  console.log(kalit); // faqat "ism" ← ID ko'rinmaydi
}

// Symbol larga maxsus usul bilan kirish
console.log(Object.getOwnPropertySymbols(ob)); // [Symbol(id)]
console.log(ob[ID]); // 42 ← to'g'ridan kirish

Bu xususiyat kutubxonalar uchun qulay — ichki ma'lumot foydalanuvchi for...in yoki JSON.stringify bilan ko'rmaydi.


Symbol.for — global registry

Turli fayllarda bir xil Symbol kerak bo'lsa — Symbol.for global registrdan oladi:

// a.js faylida
const A = Symbol.for("umumiy-id");

// b.js faylida — boshqa fayl, lekin bir xil Symbol
const B = Symbol.for("umumiy-id");

console.log(A === B); // true ← global registrdan, bir xil

// Oddiy Symbol bilan farqi:
const C = Symbol("umumiy-id");
console.log(A === C); // false ← lokal, boshqa

Symbol.for — "bu nom bilan allaqachon Symbol bor? Bergin. Yo'q bo'lsa — yaratgin."


O'rnatilgan Symbol lar — JavaScript ning o'zi ishlatadi

JavaScript ichki mexanizmlari ham Symbol ishlatadi. Siz ularni override qilish orqali ob'ektlaringiz xulqini o'zgartira olasiz.

Oldingi darsda ko'rgan [Symbol.iterator] — shulardan biri:

// for...of qanday ishlashini o'zgartirish
const ob = {
  malumotlar: [10, 20, 30],

  [Symbol.iterator]() {        // ← JavaScript shu metodga murojaat qiladi
    let i = 0;
    return {
      next: () => ({
        value: this.malumotlar[i],
        done:  i++ >= this.malumotlar.length,
      })
    };
  }
};

for (const qiymat of ob) {
  console.log(qiymat); // 10, 20, 30
}

Boshqa muhim o'rnatilgan Symbol lar:

Symbol.toPrimitive — ob'ekt oddiy qiymatga (son, matn) o'zgartirilganda:

const narx = {
  qiymat: 50000,
  valyuta: "so'm",

  [Symbol.toPrimitive](hint) {
    if (hint === "number") return this.qiymat;
    if (hint === "string") return `${this.qiymat} ${this.valyuta}`;
    return this.qiymat;
  }
};

console.log(+narx);        // 50000 ← hint: "number"
console.log(`${narx}`);   // "50000 so'm" ← hint: "string"
console.log(narx + 1000); // 51000 ← hint: "default"

Symbol.hasInstance — instanceof xulqini o'zgartirish:

class SonlarTo_plami {
  static [Symbol.hasInstance](qiymat) {
    return typeof qiymat === "number";
  }
}

console.log(42 instanceof SonlarTo_plami);      // true
console.log("matn" instanceof SonlarTo_plami);  // false

Tez-tez uchraydigan xatolar

Symbol ni new bilan yaratish:

// ❌ — Symbol konstruktor emas
const s = new Symbol("id"); // TypeError: Symbol is not a constructor

// ✅ — funksiya sifatida chaqiriladi
const s = Symbol("id");

Symbol ni JSON ga o'girish mumkin emas:

const ID = Symbol("id");
const ob = { ism: "Jasur", [ID]: 42 };

JSON.stringify(ob); // '{"ism":"Jasur"}' — Symbol yo'qoldi

Symbol xususiyatlar JSON da yo'qoladi. Agar ma'lumot serverga yuborilishi kerak bo'lsa — oddiy matn kalit ishlatish kerak.

Symbol() va Symbol.for() ni aralashtirish:

const a = Symbol("test");        // ← lokal, yagona
const b = Symbol.for("test");    // ← global registry dan
const c = Symbol.for("test");    // ← registry da bor — b bilan bir xil

console.log(a === b); // false
console.log(b === c); // true

Xulosa

Symbol — yagona va takrorlanmas qiymat. Har yangi Symbol dunyo da yagona.

Ob'ekt xususiyati kalit sifatida — matn kalitlar bilan to'qnashmaydi. for...in, Object.keys, JSON.stringify ko'rmaydi — "yashirin" xususiyat.

Symbol.for — global registry. Turli fayllarda bir xil Symbol olish uchun.

O'rnatilgan Symbol lar — Symbol.iterator, Symbol.toPrimitive, Symbol.hasInstance — JavaScript ning ichki mexanizmlarini o'zgartirish uchun.

Asosiy ishlatilishi: kutubxonalarda to'qnashuvsiz ichki xususiyatlar va ob'ekt xulqini sozlash.


Keyingi dars

60-dars: Proxy va Reflect