Ժառանգություն JavaScript-ում
Ժառանգություն JavaScript-ում — extends, super և prototype շղթա
JavaScript-ում ժառանգությունը հիմնված է prototype chain
-ի վրա։ ES6-ից սկսած, class սինտաքսը պարզեցրեց այս մեխանիզմը՝ extends
և super()
բանալի բառերով։ Այս բաժնում կվերլուծենք ինչպես է իրականում աշխատում class-երի ժառանգությունը՝ ներառյալ մեթոդների և հատկությունների ժառանգում, շղթայական կապը, և super
-ի դերը։
Եկեք սկսենք պարզ օրինակով, որտեղ մեկ class ժառանգում է մյուսից՝ օգտագործելով extends
և super()
։
class Animal { constructor(name) { this.name = name; }
speak() { console.log(${this.name} makes a sound); } }
class Dog extends Animal { constructor(name, breed) { super(name); // Կանչում ենք ծնողական constructor-ը this.breed = breed; }
speak() { super.speak(); // Կանչում ենք ծնողի մեթոդը console.log(${this.name} barks); } }
const d = new Dog('Rex', 'Labrador'); d.speak(); // Rex makes a sound // Rex barks
Բացատրություն․
Dog extends Animal
նշանակում է՝ Dog-ը ժառանգում է Animal-ի prototype-ը
super(name)
–ը պարտադիր է՝ եթե constructor ենք գրում երեխա class-ում
super.speak()
–ը կանչում է ծնողական class-ի մեթոդը
Երբ մենք օգտագործում ենք extends
, JavaScript-ը ստեղծում է երկու շղթա՝ մեկ prototype
օբյեկտների համար, և մեկը՝ constructor-ների միջև։
console.log(Dog.prototype.__proto__ === Animal.prototype); // true
console.log(Dog.__proto__ === Animal); // true
Այս կապերը թույլ են տալիս, որ instance-ը կարողանա մուտք գործել ինչպես իր, այնպես էլ իր ծնողների մեթոդները՝ շնորհիվ [[Prototype]]
շղթայի։
Գրաֆիկ ձևով՝
d --> Dog.prototype --> Animal.prototype --> Object.prototype
super() — constructor-ից ներսում օգտագործվում է ծնողի constructor-ը կանչելու համար։ Պետք է օգտագործել նախքան this
-ին մուտք գործելը։
constructor(name) { // this.name = name; ❌ Error super(name); // ✅ }
super.method() — օգտագործվում է ծնողական class-ի մեթոդին հասնելու համար instance մեթոդից ներսում։
speak() { super.speak(); // Կանչում է Animal.prototype.speak }
Static մեթոդներն էլ են ժառանգվում։ Եթե base class-ը ունի static method, ապա derived class-ը նույնպես կունենա այն՝ առանց կրկնակի սահմանման։
class Person { static info() { return 'I am a Person'; } }
class Developer extends Person {}
console.log(Developer.info()); // I am a Person
Եթե միևնույն մեթոդը սահմանվում է մի քանի մակարդակի class-երում, ապա JavaScript-ը օգտագործում է մոտակա մեթոդը՝ ըստ շղթայի։
class A { who() { return 'A'; } }
class B extends A { who() { return 'B'; } }
class C extends B { who() { return super.who() + '->C'; } }
const c = new C(); console.log(c.who()); // B->C
Բացատրություն․
super.who()
–ը կանչում է B-ի մեթոդը, որովհետև C-ը անմիջապես ժառանգում է B-ից։
Դու կարող ես ստեղծել “կառուցվածքային” ժառանգություն առանց class-երի՝ օգտագործելով Object.assign
։ Բայց սա չի ստեղծում պրոտոտիպային ժառանգություն։
const animalMethods = { speak() { console.log(`${this.name} speaks`); } };
function createDog(name) { const dog = { name }; return Object.assign(dog, animalMethods); }
Այս մոտեցումն աշխատում է, բայց չունի instanceof
, չի պահպանում constructor
, և պակաս մաքուր է մեծ ծրագրերում։
JavaScript-ի class inheritance համակարգը կառուցված է prototype chain
-ի վրա, սակայն ES6-ի սինտաքսը այն ներկայացնում է որպես հստակ OOP կառուցվածք։ extends
և super()
կոդերը ավելի ընթեռնելի են դարձնում ժառանգությունը, սակայն ներքուստ դրանք աշխատում են նույն prototype
սկզբունքով։
Հաջորդ մասում կքննարկենք՝ ինչպես իրականացնել պոլիմորֆիզմ JavaScript class-երում, override անել մեթոդներ և ստեղծել ընդհանուր interface-ներ տարբեր class-երի համար։