10-bo‘lim

Sinflar

Parametr xossalari, private va #, implements, abstract va sinflardagi uchta kutilmagan xatti-harakat.

🕑 26 daqiqa o‘qish 📄 840 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Sinf asosi
  2. Parametr xossalari
  3. Ko'rinish belgilari
  4. Birinchi kutilmagan narsa: private ish vaqtida yo'q
  5. Ikkinchi kutilmagan narsa: private tuzilmaviy turlashni buzadi
  6. implements
  7. Maydon albatta to'ldirilishi kerak
  8. Getter va setter
  9. abstract va static
  10. Uchinchi kutilmagan narsa: metod this ni yo'qotadi
  11. Xulosa

Sinflar TypeScript ning ixtirosi emas - ular JavaScript da bor. TypeScript ularga turlar, ko'rinish belgilari va implements qo'shadi.

Bu bobda uchta kutilmagan narsa bor: private ish vaqtida yo'qoladi, private tuzilmaviy turlashni buzadi, va metod o'zining this ini yo'qotadi.

Sinf asosi #

TS
class Mahsulot {
  nomi: string;
  narx: number;

  constructor(nomi: string, narx: number) {
    this.nomi = nomi;
    this.narx = narx;
  }

  chegirma(foiz: number): number {
    return this.narx - (this.narx * foiz) / 100;
  }
}

const m = new Mahsulot("Olma", 12000);
console.log(m.nomi, m.chegirma(20));
Terminal
tsx src/sinf.ts
Natija
Olma 9600

Maydonlar sinf tanasida e'lon qilinadi, konstruktorda to'ldiriladi.

Parametr xossalari #

Yuqoridagi kodda nomi uch marta yozildi. TypeScript buni qisqartiradi:

TS
class Mahsulot {
  constructor(
    public nomi: string,
    private narx: number,
    readonly id: number = 1,
  ) {}

  chop(): string {
    return `${this.nomi}: ${this.narx}`;
  }
}

const m = new Mahsulot("Olma", 12000);
console.log(m.chop(), m.nomi, m.id);
Terminal
tsx src/param.ts
Natija
Olma: 12000 Olma 1

Konstruktor parametriga public, private, protected yoki readonly qo'yilsa, TypeScript maydonni o'zi yaratib, qiymatni o'zi tayinlaydi. Sinf tanasi butunlay bo'sh qoldi.

Bu - TypeScript ga xos

Parametr xossalari JavaScript da yo'q. Kod JavaScript ga o'girilganda ular oddiy this.nomi = nomi; qatorlariga aylanadi.

Bu - darslikdagi kam sonli "faqat TypeScript da bor" imkoniyatlardan biri. Qolganlari: enum, namespace va parametr dekoratorlari.

Ko'rinish belgilari #

TS
class Mahsulot {
  constructor(private narx: number) {}
}

const m = new Mahsulot(12000);
console.log(m.narx);
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/priv.ts(6,15): error TS2341: Property 'narx' is private and only
accessible within class 'Mahsulot'.
BelgiKim ko'radi
public (standart)Hamma
protectedSinf va undan meros olganlar
privateFaqat shu sinf

Birinchi kutilmagan narsa: private ish vaqtida yo'q #

TS
class Mahsulot {
  constructor(private narx: number) {}
}

const m = new Mahsulot(12000);
console.log(JSON.stringify(m));
console.log(Object.keys(m).join(","));
Terminal
tsc --noEmit && echo "tsc: xato yo_q"
tsx src/priv2.ts
Natija
tsc: xato yo_q
{"narx":12000}
narx

narx JSON.stringify da ham, Object.keys da ham ko'rinib turibdi. private - faqat kompilyator uchun; kod JavaScript ga o'girilganda u yo'qoladi.

Haqiqiy shaxsiy maydon uchun JavaScript ning # yozuvi bor:

TS
class Mahsulot {
  #narx: number;

  constructor(narx: number) {
    this.#narx = narx;
  }

  chop(): string {
    return String(this.#narx);
  }
}

const m = new Mahsulot(12000);
console.log(m.chop());
console.log(JSON.stringify(m));
console.log(Object.keys(m).length);
Terminal
tsx src/xesh.ts
Natija
12000
{}
0

#narx tashqaridan umuman ko'rinmaydi - na JSON da, na Object.keys da, na as any orqali.

Qaysi birini tanlash
MaqsadTanlov
Jamoaga "bunga tegmang" deyishprivate
Maxfiy ma'lumotni yashirish#
Kutubxona API sini yopish#
JSON.stringify dan chiqarib tashlash#

private - hujjat, # - qulf.

Ikkinchi kutilmagan narsa: private tuzilmaviy turlashni buzadi #

8-bobda ko'rdik: TypeScript nomga emas, tuzilmaga qaraydi. Sinflarda bitta istisno bor:

TS
class A {
  constructor(private x: number) {}
}

class B {
  constructor(private x: number) {}
}

let a: A = new A(1);
const b: B = new B(2);
a = b;
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/tuzilma.ts(11,1): error TS2322: Type 'B' is not assignable to type
'A'.
  Types have separate declarations of a private property 'x'.

Ikkala sinf bir xil - bir xil nomli, bir xil turdagi maydon. Lekin private maydonlar alohida e'lon qilingan bo'lgani uchun mos kelmadi.

private ni olib tashlasak:

TS
class A {
  constructor(public x: number) {}
}

class B {
  constructor(public x: number) {}
}

let a: A = new A(1);
const b: B = new B(2);
a = b;
console.log(a.x);
Terminal
tsx src/tuzilma2.ts
Natija
2

Endi ishladi. Ya'ni private sinfga nomga asoslangan xatti-harakat qo'shadi - bu butun tur tizimidagi yagona joy.

Teskari tomoni ham qiziq - oddiy obyekt sinf turiga mos keladi:

TS
class Mahsulot {
  constructor(public nomi: string) {}
}

const m: Mahsulot = { nomi: "Olma" };
console.log(m.nomi, m instanceof Mahsulot);
Terminal
tsx src/obyekt.ts
Natija
Olma false

new ishlatilmadi, lekin tur mos keldi - chunki tuzilma bir xil. instanceof esa false qaytardi. Test yozishda bu foydali, lekin instanceof ga tayanadigan kodda xavfli.

private va # : bir xil maqsad, boshqa kuch private narx TypeScript kalit so'zi tsc tashqaridan murojaatni to'xtatadi JS ga o'girilganda yo'qoladi JSON.stringify: {"narx":12000} Object.keys: narx as any orqali o'qish mumkin Hujjat #narx JavaScript ning o'z imkoniyati tsc tashqaridan murojaatni to'xtatadi JS da ham saqlanib qoladi JSON.stringify: {} Object.keys: bo'sh as any ham yordam bermaydi Qulf Yon ta'sir: private maydonli ikkita bir xil sinf bir-biriga MOS KELMAYDI Bu - tuzilmaviy turlash qoidasidan yagona istisno.
private niyatni, # esa chegarani bildiradi

implements #

TS
interface Sotiladigan {
  nomi: string;
  narxi(): number;
}

class Mahsulot implements Sotiladigan {
  constructor(
    public nomi: string,
    private asos: number,
  ) {}

  narxi(): number {
    return this.asos;
  }
}

const m = new Mahsulot("Olma", 12000);
console.log(m.nomi, m.narxi());
Terminal
tsx src/implem.ts
Natija
Olma 12000
TS
interface Sotiladigan {
  nomi: string;
  narxi(): number;
}

class Mahsulot implements Sotiladigan {
  constructor(public nomi: string) {}
}
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/implem2.ts(6,7): error TS2420: Class 'Mahsulot' incorrectly
implements interface 'Sotiladigan'.
  Property 'narxi' is missing in type 'Mahsulot' but required in type
'Sotiladigan'.

implements faqat tekshiradi - u sinfga hech narsa qo'shmaydi va ish vaqtida iz qoldirmaydi.

Maydon albatta to'ldirilishi kerak #

TS
class Mahsulot {
  nomi: string;
  narx: number = 0;
}
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/init.ts(2,3): error TS2564: Property 'nomi' has no initializer and is
not definitely assigned in the constructor.

Bu strictPropertyInitialization ning ishi (u strict ga kiradi). narx ga standart qiymat berilgani uchun shikoyat yo'q.

Uchta yechim: standart qiymat berish, konstruktorda to'ldirish, yoki turni string | undefined qilish.

Getter va setter #

TS
class Mahsulot {
  #narx = 0;

  get narx(): number {
    return this.#narx;
  }

  set narx(yangi: number) {
    if (yangi < 0) throw new Error("manfiy narx");
    this.#narx = yangi;
  }
}

const m = new Mahsulot();
m.narx = 12000;
console.log(m.narx);

try {
  m.narx = -5;
} catch (e) {
  console.log((e as Error).message);
}
Terminal
tsx src/getset.ts
Natija
12000
manfiy narx

m.narx oddiy maydondek ko'rinadi, aslida metod chaqiriladi.

catch (e) dagi e ning turi - unknown, Error emas. Buni strict ichidagi useUnknownInCatchVariables talab qiladi, chunki JavaScript da istalgan qiymatni tashlash mumkin.

abstract va static #

TS
abstract class Shakl {
  static sanoq = 0;

  constructor() {
    Shakl.sanoq++;
  }

  abstract yuza(): number;

  chop(): string {
    return `yuza: ${this.yuza().toFixed(1)}`;
  }
}

class Kvadrat extends Shakl {
  constructor(private tomon: number) {
    super();
  }

  yuza(): number {
    return this.tomon ** 2;
  }
}

const k = new Kvadrat(3);
console.log(k.chop(), Shakl.sanoq);
Terminal
tsx src/abstr.ts
Natija
yuza: 9.0 1

chop() this.yuza() ni chaqiradi - garchi Shakl uning tanasini bilmasa ham. Bu - shablon naqshi.

TS
abstract class Shakl {
  abstract yuza(): number;
}

const s = new Shakl();
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/abstr2.ts(5,11): error TS2511: Cannot create an instance of an
abstract class.

Uchinchi kutilmagan narsa: metod this ni yo'qotadi #

TS
class Hisob {
  #jami = 0;

  qosh(n: number): void {
    this.#jami += n;
  }

  get jami(): number {
    return this.#jami;
  }
}

const h = new Hisob();
[1, 2, 3].forEach(h.qosh);
console.log(h.jami);
Terminal
tsc --noEmit && echo "tsc: xato yo_q"
tsx src/this1.ts 2>&1 | grep -oE "TypeError.*" | head -1
Natija
tsc: xato yo_q
TypeError: Cannot read properties of undefined (reading '#jami')

h.qosh - shunchaki funksiya qiymati. U h dan ajratilganda this bilan bog'lanishini yo'qotadi. Bu JavaScript ning qoidasi, TypeScript uni standart holatda tekshirmaydi.

Eng oddiy yechim - metodni strelkali xossa qilish:

TS
class Hisob {
  #jami = 0;

  qosh = (n: number): void => {
    this.#jami += n;
  };

  get jami(): number {
    return this.#jami;
  }
}

const h = new Hisob();
[1, 2, 3].forEach(h.qosh);
console.log(h.jami);
Terminal
tsx src/this2.ts
Natija
6

Strelkali funksiya this ni yaratilgan joydan oladi va uni hech qachon yo'qotmaydi.

Muammoni kompilyatsiyada tutish ham mumkin - this parametri orqali:

TS
class Hisob {
  #jami = 0;

  qosh(this: Hisob, n: number): void {
    this.#jami += n;
  }
}

const h = new Hisob();
const f = h.qosh;
f(1);
Terminal
tsc --noEmit 2>&1 | fold -sw 74
Natija
src/this3.ts(11,1): error TS2684: The 'this' context of type 'void' is
not assignable to method's 'this' of type 'Hisob'.

this: Hisob - soxta birinchi parametr. U ish vaqtida mavjud emas, lekin kompilyatorga "bu metodni Hisob nusxasidan ajratmang" deb aytadi.

Strelkali xossaning narxi

qosh = (n) => {...} har bir nusxa uchun alohida funksiya yaratadi. Oddiy metod esa prototipda bir marta saqlanadi.

Xotirathis
MetodBitta nusxaYo'qolishi mumkin
Strelkali xossaHar obyektdaDoim bog'langan

Minglab obyekt yaratilmasa, farq sezilmaydi. Shubhali joylarda esa this: Hisob parametri bepul himoya beradi.

Xulosa #

  • Sinf maydonlariga tur yoziladi; konstruktor parametrlariga public/private/readonly qo'yilsa, maydon avtomatik yaratiladi.
  • Parametr xossalari - TypeScript ga xos imkoniyat, JavaScript da yo'q.
  • private va protected faqat kompilyatorda ishlaydi - JavaScript ga o'girilganda yo'qoladi.
  • #maydon - JavaScript ning haqiqiy shaxsiy maydoni; u JSON.stringify va Object.keys da ko'rinmaydi.
  • private maydonli ikkita bir xil sinf bir-biriga mos kelmaydi - bu tuzilmaviy turlashdagi yagona istisno.
  • Oddiy obyekt sinf turiga mos keladi, lekin instanceof false qaytaradi.
  • implements faqat tekshiradi; sinfga hech narsa qo'shmaydi.
  • strictPropertyInitialization har bir maydonni to'ldirishni talab qiladi (TS2564).
  • catch (e) dagi e - unknown; ishlatishdan oldin tekshirish yoki as Error kerak.
  • abstract sinfdan nusxa yasab bo'lmaydi; abstract metod merosxo'rda amalga oshiriladi.
  • Metod nusxadan ajratilganda this ni yo'qotadi - strelkali xossa yoki this: Sinf parametri bilan himoyalaning.
Amaliy topshiriq
  1. Ikkita maydonli va bitta metodli sinf yozing.
  2. Uni parametr xossalari bilan qayta yozib, qatorlar sonini solishtiring.
  3. private maydonni JSON.stringify bilan chop etib, ko'rinishini tasdiqlang.
  4. Uni # ga o'zgartirib, natijaning {} bo'lishini ko'ring.
  5. Bir xil private maydonli ikkita sinf yozib, TS2322 ni oling.
  6. Sinf turidagi o'zgaruvchiga oddiy obyekt bering va instanceof natijasini tekshiring.
  7. interface yozib, uni implements qiling va bir metodni ataylab unuting.
  8. Maydonga qiymat bermasdan TS2564 ni chaqiring, keyin uch xil usulda tuzating.
  9. Metodni forEach ga to'g'ridan-to'g'ri berib, dasturni yiqiting.
  10. Uni this: Sinf parametri bilan kompilyatsiya vaqtida tutiladigan qiling.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.