Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement classical class inheritance through prototypes

I would like to implement the following behavior in JS. Please note that the syntax is symbolic.

This is my parent class

class = TList {
   FList: array;

   function AddElement(Ele) {
        Flist.Add(Ele)
   };

   function RemoveEle(Ele) {
        FList.Remove(Ele)
   };   
}

Now I'm going to inherit from this class. My child class should automatically have all the properties of the parent and should be able to extend them without rewriting the code.

class = TAlertList(inherit from TList) {

   function AddElement(Ele) {
      Alert('element will be added');
      call.parent.AddElement(Ele)
   };

   function RemoveElement(Ele) {
     call.parent.RemoveElement(Ele);
     Alert('element removed');
   }

}

Please note how I inherit the parent methods at places I wish.

Now I should be able to create an object from my child class and do the following.

MyAlertList = new TAlertList;
MyAlertList.Add('hello');
console.log(MyAlertList.FList);

I should be able to inherit more child classes from TAlertList and be able to change the existing behavior. I need to do this in pure ES5 without using any libraries. Standard OOP practices are expected.

like image 573
Charlie Avatar asked May 14 '26 15:05

Charlie


1 Answers

Please note that the TList constructor should be applied to the TAlertList instance;

ES5, first set up the base constructor

function TList() {
    this.Flist = [];
    // ...
}

TList.prototype = {
    constructor: TList,
    AddElement: function AddElement(Ele) {
        this.Flist.push(Ele);
    },
    RemoveEle: function RemoveEle(Ele) {
        var i = this.Flist.lastIndexOf(Ele);
        if (i !== -1)
            this.Flist.splice(i, 1);
    }
};

Next set up the constructor which extends it, see how this means calling the base constructor on the instance being created by the extended constructor and creating a prototype object which inherits the prototype of the base constructor

function TAlertList() {
    // construct from base
    TList.call(this);
    // further construct
    // ...
}
TAlertList.prototype = Object.create(TList.prototype);
TAlertList.prototype.constructor = TAlertList;

// depending on how you want to reference stuff
TAlertList.prototype.AddElement = function AddElement(Ele) {
    alert('element will be added');
    TList.prototype.AddElement.call(this, Ele);
};
TAlertList.prototype.RemoveElement = function RemoveElement(Ele) {
    TList.prototype.RemoveEle.call(this, Ele);
    alert('element removed');
};

ES6 syntax makes use of the super keyword

class TList {
    constructor() {
        this.FList = [];
    }
    AddElement(Ele) {
        this.Flist.push(Ele);
    }
    RemoveEle(Ele) {
        var i = this.Flist.lastIndexOf(Ele);
        if (i !== -1)
            this.Flist.splice(i, 1);
    }
}

class TAlertList extends TList {
    constructor() {
        super();
    }
    AddElement(Ele) {
        alert('element will be added');
        super.AddElement(Ele);
    }
    RemoveElement(Ele) {
        super.RemoveEle(Ele);
        alert('element removed');
    }
}

Back to ES5, generalising as a factory so you can see a sort of algorithm of how to do it

function extend(baseConstructor, extendedConstructor, prototypeLayer) {
    function Constructor() {
        var i = 0, j = 0, args = Array.prototype.slice.call(arguments);

        i = j, j += baseConstructor.length;
        baseConstructor.apply(this, args.slice(i, j));

        i = j, j = args.length;
        extendedConstructor.apply(this, args.slice(i, j));
    }
    Object.defineProperty(Constructor, 'length', { // fix .length
        value: baseConstructor.length + extendedConstructor.length,
        configurable: true
    });
    Constructor.prototype = Object.create(baseConstructor.prototype);
    Constructor.prototype.constructor = Constructor;
    Object.assign(Constructor.prototype, prototypeLayer);
    return Constructor;
}

So then

function Foo(x) {this.foo = x;}
Foo.prototype.fizz = 1;
var Bar = extend(Foo, function (x) {this.bar = x;}, {buzz: 1});
// ...
var b = new Bar('foo', 'bar');
b.foo; // "foo"
b.bar; // "bar"
b instanceof Foo; // true
b instanceof Bar; // true
b.fizz; // 1
b.buzz; // 1

Please note that this is an example of the algorithm you should be following when you write each extended constructor, not production code

like image 159
Paul S. Avatar answered May 16 '26 05:05

Paul S.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!