JavaScript და მემკვიდრეობა – ნაწილი 1

კლასების მემკვიდრეობა ერთერთი მთავარი შემადგენელი ნაწილია ობიექტზე ორიენტირებული პროგრამირებისა. თუმცა JavaScript – ში მემკვიდრეობის რეალიზაცია განსხვავებულია ისეთი ენებისგან როგორიც არის Java, C# და PHP, შედარებით ბუნდოვანი და რთული გასაგებია რამდენადაც ამ ენაში მემკვიდრეობის რეალიზაციის რამდენიმე გზა არსებობს.

თავიდან გადავხედოთ მემკვიდრეობის რეალიზაციას Java-ში:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Base {
    public String paramOne;
    public String paramTwo;
   
    //constructor
    public Base(String paramOne, String paramTwo) {
      this.paramOne = paramOne;
      this.paramTwo = paramTwo;
    }
   
    public String baseMethod() {
      return "this is base method";
    }
   
}

public class Child extends Base {
 
  public String paramThree;
 
        //constructor
  public Child(String paramOne, String paramTwo) {
                /*მშობელი კლასის კონსტრუქტორის ცხადად გამოძახება აუცილებელია
                   რადგან მშობელ კლასში არ არის რეალიზებუილი ნაგულისხმები(უპარამეტრო)
                   კონსტრუქტორი*/

    super(paramOne, paramTwo);
    this.paramTrhee =  = "param three";
  }
 
  public static void main(String[] args) {
   
    Child child = new Child("param one", "param two");
   
      //outputs "param one" paramOne is derived from Base
    System.out.println(child.paramOne);
      //outputs "param two" paramTwo is derived from Base
    System.out.println(child.paramTwo);
      //outputs "param three" paramThree is a member of Child
    System.out.println(child.paramThree);
      //outputs "this is base method" baseMethod is derived from Base
    System.out.println(child.baseMethod()); //outputs ""
   
  }
 
}

კოდში ჩანს რომ გვაქვს ორი Base და Child კლასი რომელიც არის Base კლასის მემკვიდრე. ორივე კლასის კონსტრუქტორებს აქვთ მსგავსი სიგნატურა, ხოლო Child კონსტრუქტორიდან იძახება მშობელი Base კლასის კონსტრუქტორი super(paramOne, paramTwo);. main მეთოდში უბრალოდ იქმნება Child კლასის ახალი ობიექტი, შემდეგ კი ერთმანეთის მიყოლებით ეკრანზე ვბეჭდავთ კლასის ყველა ცვლადსა და ვიძახებთ baseMethod მეთოდს.

როგორ მივიღოთ JavaScript – ში იგივე შედეგი? ამ ენაში ხომ არ არსებობს class – ის პირდაპირი ცნება, ასევე არ არსებობს extends – ის პირდაპირ შესატყვისი და კონსტრუქტორიც Java-სგან განსხვავებულია.

პირველ რიგში დავწეროთ შესაბამისი JavaScript კოდი:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function Base(paramOne, paramTwo) {
    this.paramOne = paramOne;
    this.paramTwo = paramTwo;
    this.baseMethod = function() {
        return "this is base method";
    }
}

function Child(paramOne, paramTwo) {
    this.base = Base;
    this.base(paramOne, paramTwo);
    this.paramThree = "param three";
}

var child = new Child("param one", "param two");

//outputs "param one" paramOne is derived from Base
document.write(child.paramOne);
document.write("<br />");
//outputs "param two" paramTwo is derived from Base
document.write(child.paramTwo);
document.write("<br />");
//outputs "param three" paramThree is a member of Child
document.write(child.paramThree);
document.write("<br />");
//outputs "this is base method" baseMethod is derived from Base
document.write(child.baseMethod());

თუ შევასრულებთ ამ კოდს მივიღებთ Java კოდის იდენტურ რეზულტას. თუმცა თუ შევადარებთ კოდს განსხვავება აშკარაა და საჭიროებს დეტალურ განხილვას.

პირველ რიგში ყურადღება უნდა მივაქციოთ იმას რომ JavaScript-ის რეალიზაციაში არსად არ არის ნახსენები class და Base და Child კლასები აღწერილია როგორც ჩვეულებრივი ფუნქციები. ასევე ცხადად არ არის აღწერილი კლასის კონსტრუქტორები (მაგ. Java-ში კონსტრუქტორს უნდა ერქვას კლასის სახელი და არ უნდა ქონდეს მითითებული დასაბრუნებელი მნიშვნელობის ტიპი, ასევე შესაძლებელია კონსტრუქტორს მივუთითოთ ნებისმიერი წვდომის(მათ შორის private) მოდიფიკატორი).

რამდენადაც JavaScript-ში არ არსებობს კლასისგან განცალკევებული კონსტრუქტორის ცნება, შესაძლებელია რომ კონსტრუქტორად გამოვიყენოთ ნებისმიერი ფუნქცია. მოცემელ შემთხვევაში კონსტრუქტორებად შეგვიძლია განვიხილოთ თვითონ Base და Child ფუნქციები. ორივე მათგანი ღებულობს პარამეტრებს და ორივე მათგანი შეიცავს კოდს რომელიც ავტომატურად შესრულდება new ოპერატორის გამოყენების თანავე.

ანალოგიებს თუ მოვიყვანთ შეგვიძლია ვთქვათ რომ:

1
function Base(paramOne, paramTwo) {}

არის იგივე რაც Java-ში:

1
2
3
class Base {    
    public Base(String paramOne, String paramTwo) {}
}

როგორ ხდება მემკვიდრეობის რეალიზაცია JavaScript-ში? Child კონსტრუქტორს თუ დავაკვირდებით მასში პირველ ორ სტრიქონზე წერია შემდეგი კოდი:

this.base = Base;
this.base(paramOne, paramTwo);

რა ხდება ამ კონკრეტულ შემთხვევაში? პირველ რიგში Child კონსტრუქტორში ვქმნით base(ამ შემთხვევაში base არ არის სავალდებულო დასახელება წევრისათვის) წევრს და მას ვანიჭებთ Base კონსტრუქტორს(დიახ სწორედ კონსტრუქტორს და არა ფუნქციას), შემდეგ ხაზზე ხდება Base კონსტრუქტორის გამოძახება მხოლოდ base თვისების მეშვეობით, აქ ყურადღება უნდა მივაქციოთ იმ ფაქტს რომ არავითარი new ოპერატორი არ გამოიყენება, უბრალოდ ხდება Base კონსტრუქტორის გამოძახება. კონსტრუქტორის ასეთი გამოძახება უზრუნველყოფს, რომ მოხდება Base კლასში განსაზღვრული ყველა წევრის ინიციალიზაცია (paramOne, paramTwo და baseMethod) და კოპირება(დიახ ზუსტად კოპირება) Child კლასში. შედეგად ვღებულობთ იმას რომ Child კლასს გარდა მის მიერ განსაზღვრული წევრებისა გააჩნია ასევე ყველა ის წევრი რომელიც იყო განსაზღვრული Base კლასში.

მიუხედავად იმისა რომ ასეთი ხერხით შესაძლებელია მემკვიდრეობის განხორციელება ეს არ ნიშნავს იმას რომ საქმე გვაქვს ნამდვილ მემკვიდრეობასთან, რადგან ასეთ შემთხვევაში ხდება არა მემკვიდრული იერარქიის შექმნა(როგორც ეს ხდება Java-ს შემთხვევაში) არამედ უბრალოდ ერთი კლასის წევრების კოპირება მეორე კლასში. მსგავსი კოპირება ნიშნავს იმას რომ რამდენჯერაც გამოვიყენებთ new ოპერატორს და შევქმნით ახალ Child ობიექტს იმდენჯერ დაკოპირდება Base კლასის ყველა წევრი ამ ახლად შექმნილ ობიექტში, რაც თავისთავად შეიძლება უარყოფითად აისახოს აპლიკაციის წარმადობაზე თუ ასეთი ტიპის ბევრი ობიექტის შექმნა იქნება საჭირო.

ტეგები:

დატოვე კომენტარი:

ქართული კლავიატურა, ჩართვა/გამორთვა კლავიშით "~"