JavaScript-da sinflar vorisligi bo'yicha to'liq qo'llanma. Ishonchli va qo'llab-quvvatlanadigan ilovalar yaratish uchun turli namunalar va eng yaxshi amaliyotlar o'rganiladi.
JavaScript-da Obyektga Yo'naltirilgan Dasturlash: Sinflar Vorisligi Namunalarini O'zlashtirish
Obyektga Yo'naltirilgan Dasturlash (OYD) — bu dasturchilarga o'z kodlarini modulli va qayta ishlatiladigan tarzda tuzish imkonini beruvchi kuchli paradigma. Vorislik, OYDning asosiy tushunchasi bo'lib, bizga mavjud sinflar asosida yangi sinflar yaratish, ularning xususiyatlari va metodlarini meros qilib olish imkonini beradi. Bu kodni qayta ishlatishni rag'batlantiradi, ortiqcha takrorlanishni kamaytiradi va dasturiy ta'minotni qo'llab-quvvatlashni osonlashtiradi. JavaScript-da vorislik har birining o'z afzalliklari va kamchiliklariga ega bo'lgan turli namunalar orqali amalga oshiriladi. Ushbu maqolada an'anaviy prototipik vorislikdan tortib zamonaviy ES6 sinflari va undan keyingi namunalargacha bo'lgan barcha usullar keng qamrovli tarzda o'rganiladi.
Asoslarni Tushunish: Prototip va Prototip Zanjiri
Aslida, JavaScript-ning vorislik modeli prototiplarga asoslangan. JavaScript-dagi har bir obyekt o'zi bilan bog'liq prototip obyektiga ega. Obyektning biror xususiyati yoki metodiga murojaat qilganingizda, JavaScript avval uni obyektning o'zida qidiradi. Agar topilmasa, u obyektning prototipini qidiradi. Bu jarayon xususiyat topilguncha yoki zanjirning oxiriga (odatda `null`) yetguncha prototip zanjiri bo'ylab davom etadi.
Bu prototipik vorislik Java yoki C++ kabi tillarda mavjud bo'lgan klassik vorislikdan farq qiladi. Klassik vorislikda sinflar to'g'ridan-to'g'ri boshqa sinflardan meros oladi. Prototipik vorislikda esa obyektlar to'g'ridan-to'g'ri boshqa obyektlardan (yoki aniqrog'i, o'sha obyektlar bilan bog'liq prototip obyektlaridan) meros oladi.
`__proto__` Xususiyati (Eskirgan, lekin Tushunish uchun Muhim)
Rasman eskirgan bo'lsa-da, `__proto__` xususiyati (ikki pastki chiziq, proto, ikki pastki chiziq) obyektning prototipiga to'g'ridan-to'g'ri kirish imkonini beradi. Uni production kodida ishlatmaslik kerak bo'lsa-da, uni tushunish prototip zanjirini tasavvur qilishga yordam beradi. Masalan:
const animal = {
name: 'Generic Animal',
makeSound: function() {
console.log('Generic sound');
}
};
const dog = {
name: 'Dog',
breed: 'Golden Retriever'
};
dog.__proto__ = animal; // "animal" ni "dog" ning prototipi sifatida o'rnatadi
console.log(dog.name); // Chiqaradi: Dog ("dog" o'zining "name" xususiyatiga ega)
console.log(dog.breed); // Chiqaradi: Golden Retriever
console.log(dog.makeSound()); // Chiqaradi: Generic sound ("animal" dan meros olingan)
Ushbu misolda `dog` obyekti `makeSound` metodini prototip zanjiri orqali `animal` obyektidan meros qilib oladi.
`Object.getPrototypeOf()` va `Object.setPrototypeOf()` Metodlari
Bular obyektning prototipini olish va o'rnatish uchun `__proto__` ga nisbatan standartlashtirilgan va ishonchli yondashuvni taklif qiluvchi afzalroq usullardir. Prototip munosabatlarini boshqarish uchun ushbu metodlardan foydalanish tavsiya etiladi.
const animal = {
name: 'Generic Animal',
makeSound: function() {
console.log('Generic sound');
}
};
const dog = {
name: 'Dog',
breed: 'Golden Retriever'
};
Object.setPrototypeOf(dog, animal);
console.log(dog.name); // Chiqaradi: Dog
console.log(dog.breed); // Chiqaradi: Golden Retriever
console.log(dog.makeSound()); // Chiqaradi: Generic sound
console.log(Object.getPrototypeOf(dog) === animal); // Chiqaradi: true
Prototip yordamida Klassik Vorislikni Simulyatsiya Qilish
JavaScript-da boshqa tillardagi kabi klassik vorislik mavjud bo'lmasa-da, biz uni konstruktor funksiyalari va prototiplar yordamida simulyatsiya qilishimiz mumkin. Bu yondashuv ES6 sinflari kiritilishidan oldin keng tarqalgan edi.
Konstruktor Funksiyalari
Konstruktor funksiyalari `new` kalit so'zi yordamida chaqiriladigan oddiy JavaScript funksiyalaridir. Konstruktor funksiyasi `new` bilan chaqirilganda, u yangi obyekt yaratadi, `this` ni shu obyektga ishora qiladigan qilib belgilaydi va yangi obyektni yashirin tarzda qaytaradi. Konstruktor funksiyasining `prototype` xususiyati yangi obyektning prototipini aniqlash uchun ishlatiladi.
function Animal(name) {
this.name = name;
}
Animal.prototype.makeSound = function() {
console.log('Generic sound');
};
function Dog(name, breed) {
Animal.call(this, name); // "name" xususiyatini ishga tushirish uchun Animal konstruktorini chaqirish
this.breed = breed;
}
// Dog'ning prototipini Animal'ning yangi namunasiga o'rnatish. Bu vorislik aloqasini o'rnatadi.
Dog.prototype = Object.create(Animal.prototype);
// Dog'ning prototipidagi konstruktor xususiyatini Dog'ning o'ziga ishora qilish uchun to'g'rilash.
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log('Woof!');
};
const myDog = new Dog('Buddy', 'Labrador');
console.log(myDog.name); // Chiqaradi: Buddy
console.log(myDog.breed); // Chiqaradi: Labrador
console.log(myDog.makeSound()); // Chiqaradi: Generic sound (Animal'dan meros olingan)
console.log(myDog.bark()); // Chiqaradi: Woof!
console.log(myDog instanceof Animal); // Chiqaradi: true
console.log(myDog instanceof Dog); // Chiqaradi: true
Tushuntirish:
- `Animal.call(this, name)`: Ushbu qator `Dog` konstruktori ichida `Animal` konstruktorini chaqiradi va yangi `Dog` obyektida `name` xususiyatini o'rnatadi. Bu ota-sinfda aniqlangan xususiyatlarni ishga tushirish usulidir. `.call` metodi bizga funksiyani ma'lum bir `this` konteksti bilan chaqirish imkonini beradi.
- `Dog.prototype = Object.create(Animal.prototype)`: Bu vorislik sozlamasining asosidir. `Object.create(Animal.prototype)` prototipi `Animal.prototype` bo'lgan yangi obyekt yaratadi. Keyin biz bu yangi obyektni `Dog.prototype` ga tayinlaymiz. Bu vorislik munosabatini o'rnatadi: `Dog` nusxalari `Animal` prototipidan xususiyatlar va metodlarni meros qilib oladi.
- `Dog.prototype.constructor = Dog`: Prototipni o'rnatgandan so'ng, `Dog.prototype` dagi `constructor` xususiyati noto'g'ri `Animal` ga ishora qiladi. Biz uni `Dog` ning o'ziga ishora qilish uchun qayta o'rnatishimiz kerak. Bu `Dog` nusxalarining konstruktorini to'g'ri aniqlash uchun muhimdir.
- `instanceof`: `instanceof` operatori obyektning ma'lum bir konstruktor funksiyasining (yoki uning prototip zanjirining) nusxasi ekanligini tekshiradi.
Nega `Object.create`?
`Object.create(Animal.prototype)` dan foydalanish juda muhim, chunki u `Animal` konstruktorini chaqirmasdan yangi obyekt yaratadi. Agar biz `new Animal()` dan foydalansak, vorislik sozlamasining bir qismi sifatida bexosdan `Animal` nusxasini yaratgan bo'lar edik, bu esa biz istagan narsa emas. `Object.create` keraksiz yon ta'sirlarsiz prototipik aloqani o'rnatishning toza usulini ta'minlaydi.
ES6 Sinflari: Prototipik Vorislik uchun Sintaktik Shakar
ES6 (ECMAScript 2015) `class` kalit so'zini taqdim etdi, bu esa sinflarni va vorislikni aniqlash uchun yanada tanish sintaksisni ta'minlaydi. Biroq, ES6 sinflari aslida hali ham prototipik vorislikka asoslanganligini yodda tutish muhim. Ular prototiplar bilan ishlashning qulayroq va o'qilishi oson usulini ta'minlaydi.
class Animal {
constructor(name) {
this.name = name;
}
makeSound() {
console.log('Generic sound');
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // Animal konstruktorini chaqirish
this.breed = breed;
}
bark() {
console.log('Woof!');
}
}
const myDog = new Dog('Buddy', 'Labrador');
console.log(myDog.name); // Chiqaradi: Buddy
console.log(myDog.breed); // Chiqaradi: Labrador
console.log(myDog.makeSound()); // Chiqaradi: Generic sound
console.log(myDog.bark()); // Chiqaradi: Woof!
console.log(myDog instanceof Animal); // Chiqaradi: true
console.log(myDog instanceof Dog); // Chiqaradi: true
Tushuntirish:
- `class Animal { ... }`: `Animal` nomli sinfni aniqlaydi.
- `constructor(name) { ... }`: `Animal` sinfi uchun konstruktorni aniqlaydi.
- `extends Animal`: `Dog` sinfi `Animal` sinfidan meros olishini bildiradi.
- `super(name)`: `name` xususiyatini ishga tushirish uchun ota-sinfning (`Animal`) konstruktorini chaqiradi. `super()` hosilaviy sinfning konstruktorida `this` ga murojaat qilishdan oldin chaqirilishi kerak.
ES6 sinflari obyektlarni yaratish va vorislik munosabatlarini boshqarish uchun toza va ixcham sintaksisni ta'minlaydi, bu esa kodni o'qish va qo'llab-quvvatlashni osonlashtiradi. `extends` kalit so'zi quyi sinflarni yaratish jarayonini soddalashtiradi va `super()` kalit so'zi ota-sinfning konstruktori va metodlarini chaqirishning oddiy usulini ta'minlaydi.
Metodni Qayta Yozish
Ham klassik simulyatsiya, ham ES6 sinflari ota-sinfdan meros qilib olingan metodlarni qayta yozishga imkon beradi. Bu sizga bola sinfda metodning ixtisoslashtirilgan implementatsiyasini taqdim etishingiz mumkinligini anglatadi.
class Animal {
constructor(name) {
this.name = name;
}
makeSound() {
console.log('Generic sound');
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
makeSound() {
console.log('Woof!'); // makeSound metodini qayta yozish
}
bark() {
console.log('Woof!');
}
}
const myDog = new Dog('Buddy', 'Labrador');
myDog.makeSound(); // Chiqaradi: Woof! (Dog'ning implementatsiyasi)
Ushbu misolda `Dog` sinfi `makeSound` metodini qayta yozib, "Woof!" chiqaradigan o'z implementatsiyasini taqdim etadi.
Klassik Vorislikdan Tashqari: Alternativ Namunalar
Klassik vorislik keng tarqalgan namuna bo'lsa-da, u har doim ham eng yaxshi yondashuv emas. Ba'zi hollarda, miksinlar va kompozitsiya kabi alternativ namunalar ko'proq moslashuvchanlikni taklif qiladi va vorislikning potentsial tuzoqlaridan qochadi.
Miksinlar (Mixins)
Miksinlar — bu vorislikdan foydalanmasdan sinfga funksionallik qo'shish usuli. Miksin — bu boshqa sinflarga "aralashtirilishi" mumkin bo'lgan metodlar to'plamini taqdim etadigan sinf yoki obyekt. Bu sizga murakkab vorislik ierarxiyasini yaratmasdan bir nechta sinflar bo'ylab kodni qayta ishlatish imkonini beradi.
const barkMixin = {
bark() {
console.log('Woof!');
}
};
const flyMixin = {
fly() {
console.log('Flying!');
}
};
class Dog {
constructor(name) {
this.name = name;
}
}
class Bird {
constructor(name) {
this.name = name;
}
}
// Miksinlarni qo'llash (soddalik uchun Object.assign yordamida)
Object.assign(Dog.prototype, barkMixin);
Object.assign(Bird.prototype, flyMixin);
const myDog = new Dog('Buddy');
myDog.bark(); // Chiqaradi: Woof!
const myBird = new Bird('Tweety');
myBird.fly(); // Chiqaradi: Flying!
Ushbu misolda `barkMixin` `Object.assign` yordamida `Dog` sinfiga qo'shiladigan `bark` metodini taqdim etadi. Xuddi shunday, `flyMixin` `Bird` sinfiga qo'shiladigan `fly` metodini taqdim etadi. Bu ikkala sinfga ham vorislik orqali bog'lanmasdan kerakli funksionallikka ega bo'lish imkonini beradi.
Murakkabroq miksin implementatsiyalari aralashtirish jarayonini ko'proq nazorat qilish uchun fabrika funksiyalari yoki dekoratorlardan foydalanishi mumkin.
Kompozitsiya
Kompozitsiya — vorislikka yana bir alternativa. Ota-sinfdan funksionallikni meros qilib olish o'rniga, sinf boshqa sinflarning nusxalarini komponentlar sifatida o'z ichiga olishi mumkin. Bu sizga oddiyroq obyektlarni birlashtirib, murakkab obyektlar qurish imkonini beradi.
class Engine {
start() {
console.log('Engine started');
}
}
class Wheels {
rotate() {
console.log('Wheels rotating');
}
}
class Car {
constructor() {
this.engine = new Engine();
this.wheels = new Wheels();
}
drive() {
this.engine.start();
this.wheels.rotate();
console.log('Car driving');
}
}
const myCar = new Car();
myCar.drive();
// Chiqaradi:
// Engine started
// Wheels rotating
// Car driving
Ushbu misolda `Car` sinfi `Engine` va `Wheels` dan tashkil topgan. Ushbu sinflardan meros olish o'rniga, `Car` sinfi ularning nusxalarini o'z ichiga oladi va o'z funksionalligini amalga oshirish uchun ularning metodlaridan foydalanadi. Bu yondashuv bo'sh bog'liqlikni rag'batlantiradi va turli komponentlarni birlashtirishda ko'proq moslashuvchanlikka imkon beradi.
JavaScript Vorisligi uchun Eng Yaxshi Amaliyotlar
- Vorislikdan ko'ra Kompozitsiyani Afzal Ko'ring: Iloji boricha vorislik o'rniga kompozitsiyani afzal ko'ring. Kompozitsiya ko'proq moslashuvchanlikni taklif qiladi va vorislik ierarxiyalaridan kelib chiqishi mumkin bo'lgan qattiq bog'liqlikdan qochadi.
- ES6 Sinflaridan Foydalaning: Toza va o'qilishi oson sintaksis uchun ES6 sinflaridan foydalaning. Ular prototipik vorislik bilan ishlashning zamonaviyroq va qo'llab-quvvatlanadigan usulini ta'minlaydi.
- Chuqur Vorislik Ierarxiyalaridan Saqlaning: Chuqur vorislik ierarxiyalari murakkablashishi va tushunish qiyin bo'lishi mumkin. Vorislik ierarxiyalarini sayoz va maqsadli qilib saqlang.
- Miksinlarni Ko'rib Chiqing: Murakkab vorislik munosabatlarini yaratmasdan sinflarga funksionallik qo'shish uchun miksinlardan foydalaning.
- Prototip Zanjirini Tushuning: JavaScript vorisligi bilan samarali ishlash uchun prototip zanjirini puxta tushunish zarur.
- `Object.create` dan To'g'ri Foydalaning: Klassik vorislikni simulyatsiya qilganda, ota-konstruktorni chaqirmasdan prototip munosabatini o'rnatish uchun `Object.create(Parent.prototype)` dan foydalaning.
- Konstruktor Xususiyatini To'g'rilang: Prototipni o'rnatgandan so'ng, bola sinf prototipidagi `constructor` xususiyatini bola konstruktoriga ishora qilish uchun to'g'rilang.
Kod Uslubi uchun Global Mulohazalar
Global jamoada ishlaganda, quyidagi jihatlarga e'tibor bering:
- Bir xil Nomlash Qoidalari: Barcha jamoa a'zolari, ularning ona tilidan qat'i nazar, oson tushunadigan aniq va izchil nomlash qoidalaridan foydalaning.
- Kod Izohlari: Kodingizning maqsadi va funksionalligini tushuntirish uchun keng qamrovli kod izohlarini yozing. Bu, ayniqsa, murakkab vorislik munosabatlari uchun muhim. API hujjatlarini yaratish uchun JSDoc kabi hujjatlar generatoridan foydalanishni o'ylab ko'ring.
- Internatsionalizatsiya (i18n) va Lokalizatsiya (l10n): Agar ilovangiz bir nechta tilni qo'llab-quvvatlashi kerak bo'lsa, vorislik sizning i18n va l10n strategiyalaringizga qanday ta'sir qilishi mumkinligini o'ylab ko'ring. Masalan, turli tillarga xos formatlash talablarini bajarish uchun quyi sinflardagi metodlarni qayta yozishingiz kerak bo'lishi mumkin.
- Testlash: Vorislik munosabatlaringiz to'g'ri ishlayotganligini va qayta yozilgan har qanday metodlar kutilganidek ishlayotganligini ta'minlash uchun puxta birlik testlarini yozing. Chekka holatlar va potentsial ishlash muammolarini testlashga e'tibor bering.
- Kod Ko'rib Chiqish: Barcha jamoa a'zolari eng yaxshi amaliyotlarga rioya qilayotganligini va kod yaxshi hujjatlashtirilgan va tushunish oson ekanligini ta'minlash uchun muntazam kod ko'rib chiqishlarini o'tkazing.
Xulosa
JavaScript vorisligi — qayta ishlatiladigan va qo'llab-quvvatlanadigan kod yaratish uchun kuchli vositadir. Turli vorislik namunalarini va eng yaxshi amaliyotlarni tushunib, siz ishonchli va kengaytiriladigan ilovalarni yaratishingiz mumkin. Klassik simulyatsiya, ES6 sinflari, miksinlar yoki kompozitsiyadan foydalanishni tanlaysizmi, asosiysi, o'z ehtiyojlaringizga eng mos keladigan namunani tanlash va global auditoriya uchun aniq, qisqa va tushunarli kod yozishdir.