1

I am always struggling with the JavaScript object/class inheritance thing. I also don't like the duplicate code in all the examples I can find (the name of the object needs to be written a few times).

As far as I understand, proper inheritance in JavaScript looks like this:

function Parent(v) {
    console.log('Parent', v);
}
Parent.prototype.helloParent = function() {
    console.log('hello parent');
}


function Child(v) {
    Parent.call( this, 'from child');

    console.log('Child');
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.helloChild = function() {
    console.log('hello child');
}


c = new Child();

console.log(c instanceof Child);

c.helloParent();
c.helloChild();

In this example, to extend the "Parent" object, I have to write "Child" four times, "Parent" two times. I want to type them both just once once – because of DRY.

I also don't want to define a custom function for this inheritance stuff. That just feels odd for me, to need a user function for such a fundamental functionality (and it is getting hard to read unknown code, because you never know what this specific inheritance function is doing exactly).

So I tried to find a simpler version. However I am not sure if I missed something?

function Parent(v) {
    console.log('Parent', v);

    this.helloParent = function() {
        console.log('hello parent');
    }
}


(Child = function(v) {
    this.constructor('from child');

    console.log('Child');

    this.helloChild = function() {
        console.log('hello child');
    }
}).prototype = Parent.prototype;


c = new Child();

console.log(c instanceof Child);

c.helloParent();
c.helloChild();

Is this okay or does it have serious drawbacks?

Edit: Regarding the comments, sadly it seems that it has some serious drawback. Are there any other solutions to reduce at least to write the name of the parent object multiple times?

flori
  • 14,339
  • 4
  • 56
  • 63
  • Why not put those methods on the prototype? (If you try, you might notice the first drawback). – Bergi Nov 10 '14 at 16:37
  • 2
    You're not doing inheritance and you're replacing the `Child.prototype` with the `Parent.prototype`, so they're the same object. This feels more like a code review. Consider http://codereview.stackexchange.com –  Nov 10 '14 at 16:37
  • I recommend to have a look at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript – Felix Kling Nov 10 '14 at 16:55
  • Check out this recent question I answered. It should help you understand the drawbacks and other alternatives: http://stackoverflow.com/questions/26595866/safely-inheriting-prototypes-in-javascript/26597766#26597766 – istos Nov 10 '14 at 16:55
  • Prototype and inheritance are explained here: http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR Nov 10 '14 at 23:40
  • I really don't know why you think you're writing the parents name too often. Could you please add the "correct" code without the shortenings you have done? – Bergi Nov 11 '14 at 13:22
  • @Bergi I extended my question to make clear what I want to avoid. My example is without shortenings. – flori Nov 11 '14 at 16:20

2 Answers2

0

I use two very small functions for simplifying inheritance in JavaScript:

function defclass(prototype) {
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
}

function extend(constructor, keys) {
    var prototype = Object.create(constructor.prototype);
    for (var key in keys) prototype[key] = keys[key];
    return defclass(prototype);
}

It is used as follows:

var Parent = defclass({
    constructor: function (a) {
        console.log("Parent", a);
    },
    helloParent: function () {
        console.log("helloParent");
    }
});

var Child = extend(Parent, {
    constructor: function () {
        Parent.call(this, "fromChild");
        console.log("Child");
    },
    helloChild: function () {
        console.log("helloChild");
    }
});

Finally:

var child = new Child;
console.log(child instanceof Child);
child.helloParent();
child.helloChild();

Putting it all together:

function defclass(prototype) {
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
}

function extend(constructor, keys) {
    var prototype = Object.create(constructor.prototype);
    for (var key in keys) prototype[key] = keys[key];
    return defclass(prototype);
}

var Parent = defclass({
    constructor: function (a) {
        console.log("Parent", a);
    },
    helloParent: function () {
        console.log("helloParent");
    }
});

var Child = extend(Parent, {
    constructor: function () {
        Parent.call(this, "fromChild");
        console.log("Child");
    },
    helloChild: function () {
        console.log("helloChild");
    }
});

var child = new Child;
console.log(child instanceof Child);
child.helloParent();
child.helloChild();

Hope that helps.

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • I don't understand why JS is not offering an own construct to make inheritance easier to understand and more readable as code. – flori Nov 11 '14 at 15:58
  • The short answer to that question is that JavaScript is a badly design programming language. Fortunately, the people in charge of designing the language are [aware of this problem and are fixing it](http://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes) --- although the fix won't be out for quite some time. If you want to learn more about inheritance in JavaScript then you should read my blog post: http://aaditmshah.github.io/why-prototypal-inheritance-matters/ – Aadit M Shah Nov 11 '14 at 17:51
0

oop in javascript is ugly. (at least until ES6 which supports the class and implements keywords) but even ES6 will not support multiple inheritance. I wrote a small class library (available on github) for javascript that makes creating classes and inheritance much easier to both develop and maintain. for example to create a class just do this:

ds.make.class({
    type: 'a',
    constructor: function (x) { this.val = x; },
    mul: function (s) {
        this.val *= s;
        return this;
    }
});

// now to inherit class a just do this...
ds.make.class({
    type: 'b',
    inherits: a,              
    constructor: function (x) { this.val = x; },
    sub: function (s) {
        this.val -= s;
        return this;
    }
});
var o = new b(5);
var output = o.mul(3).sub(5).val;    // output = 10
dss
  • 470
  • 5
  • 12
  • I am just thinking if it is possible to define own functions for this OOP stuff, but make them look and feel similar to what is coming with ES6? Or if there is already some standard across different frameworks that defines how OOP in < ES6 should look like? – flori Nov 15 '14 at 12:43
  • there is no standard that I know of but many prefer this type of approach because of readability... as soon as ES6 is available that will become the standard however, it will be many years before the majority of users run browsers with es6 support. probly by 2017 es6 will be the standard for classes in javascript – dss Nov 16 '14 at 07:10