JavaScript'da klasslar nima va ular prototiplar bilan qanday bog'liq?

MiddleJavaScript #javascript #classes #oop

Savol

ES6-klasslar qopqoq ostida nimani ifodalaydi, extends/super, shaxsiy maydonlar (#field) va statik a'zolar qanday ishlaydi?

Qisqa javob

JavaScript'da class — prototipli meros ustidan sintaktik shakar: qopqoq ostida klass metodlari hamon obyektning o'ziga emas, prototypega qo'yiladi. extends klasslar orasidagi prototiplar zanjirini sozlaydi, super ota-klass konstruktori va metodlariga kirish imkonini beradi. Shaxsiy maydonlar (#field) dvigatel darajasida haqiqiy inkapsulyatsiyani ta'minlaydi, static a'zolar esa instanslarga emas, klassning o'ziga tegishli.

Batafsil javob

Prototipli meros qanday tuzilgani haqida batafsil — alohida katta mavzu; bu yerda e'tibor aynan class sintaksisi nima berishida.

Sahar sifatida class. class Foo {} e'loni konstruktor-funksiya yaratadi, klass tanasida e'lon qilingan barcha metodlar Foo.prototypega qo'shiladi — xuddi function + Foo.prototype.method = ... orqali qo'lda sozlashda bo'lgani kabi. "Qo'lda" variantdan farqlar:

  • Klass metodlari sanaladigan emas (enumerable: false), Foo.prototype.method = fndan farqli o'laroq.
  • Klassni newsiz chaqirib bo'lmaydi — urinish TypeError tashlaydi.
  • Klass tanasi doim qat'iy rejimda ('use strict') bajariladi.
  • Klasslar funksiya e'lonlari kabi ko'tarilmaydi — ular e'lon qilinguncha temporal dead zone'da bo'ladi.

extends va super. class Dog extends Animal ikkita ishni bajaradi: Dog.prototype.__proto__ = Animal.prototype (instans metodlari merosi) va Dog.__proto__ = Animal (statik metodlar merosi). Konstruktordagi super(...) chaqiruvi ota-klass konstruktorini chaqiradi va agar klass biror narsadan meros olsa, thisga murojaat qilinguncha majburiy — dvigatel ota-klass mavjud bo'lganda thisni avtomatik yaratmaydi, buni super() bajaradi. Oddiy metoddagi super.method() bola klassdagi qayta aniqlashni chetlab o'tib, ota-klass prototipining metodini chaqiradi.

Shaxsiy maydonlar (#field). ES2022'dan boshlab # prefiksli maydonlar faqat klass tanasi ichidan kirish uchun mavjud — bu (avval _field orqali qilingani kabi) nomlash konventsiyasi emas, balki sintaksis va runtime darajasida ta'minlanadi. instance.#fieldga klassdan tashqarida murojaat qilish — parsing bosqichida SyntaxError. Shuningdek, shaxsiy metodlar (#method()) va shaxsiy statik maydonlar ham mavjud.

static a'zolar. static bilan e'lon qilingan xususiyat va metodlar prototypeda emas, klassning o'zida (konstruktorda) yashaydi, ya'ni instans orqali mavjud emas. Ular fabrika metodlari, instanslar hisoblagichlari, konstantalar, klassga mantiqiy bog'langan, lekin muayyan obyekt holatini talab qilmaydigan yordamchi vositalar uchun ishlatiladi.

Misol

class Animal {
  static kingdom = 'Animalia' // statik maydon
  #energy = 100 // shaxsiy maydon

  constructor(name) {
    this.name = name
  }

  static create(name) {
    // statik fabrika metodi
    return new Animal(name)
  }

  eat(amount) {
    this.#energy += amount
    return this.#energy
  }

  speak() {
    return `${this.name} ovoz chiqaradi`
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name) // this'ga murojaat qilinguncha majburiy
    this.breed = breed
  }

  speak() {
    const base = super.speak() // ota-klass metodini chaqirish
    return `${base} — vov! (${this.breed})`
  }
}

const rex = new Dog('Reks', 'Labrador')
console.log(rex.speak()) // "Reks ovoz chiqaradi — vov! (Labrador)"
console.log(rex.eat(10)) // 110
console.log(Dog.kingdom) // "Animalia" — statika ham meros olinadi
// console.log(rex.#energy) // SyntaxError: Private field must be declared

// Qopqoq ostida bu hamon prototiplar
console.log(Object.getPrototypeOf(Dog.prototype) === Animal.prototype) // true
console.log(typeof Dog) // "function" — klass bu funksiya
console.log(Dog.speak === undefined) // true — instans metodlari klassda emas

Qo'shimcha savollar

  • Nega merosxo'r konstruktorida super() chaqirilguncha thisga murojaat qilib bo'lmaydi?
  • Shaxsiy maydonlar (#field) holatni yashirish usuli sifatida closure'lardan nimasi bilan farq qiladi?
  • Klassda getter/setter'larni qanday amalga oshirish mumkin va bu qachon oddiy metodlardan ko'ra o'rinliroq?