1

In trying to port a Java app to JavaScript, I'm attempting the following inheritance technique:

var grandchild = new Grandchild();

Function.prototype.extend =
    function(parent) {
        var parentPrototype = parent.prototype;
        this.prototype = Object.create(parentPrototype);
        this.prototype.superPrototype = parentPrototype;
        this.prototype.superConstructor = parent;
        this.prototype.constructor = this;
    }
;

function Parent(){
    this.doStuff();
}

Parent.prototype.doStuff =
    function() {
    }
;

Child.extend(Parent);
function Child(){
    this.superConstructor.call(this);
}

Child.prototype.doStuff = function() {
    this.superPrototype.doStuff.call(this);
}

Grandchild.extend(Child);
function Grandchild(){
    this.superConstructor.call(this);
}

Grandchild.prototype.doStuff = function() {
    this.superPrototype.doStuff.call(this);
}

It works to one level of inheritance (i.e. var child = new Child()) but with new Grandchild() it throws an Uncaught RangeError: Maximum call stack size exceeded because it gets stuck in infinite recursion on function Child().

  1. What exactly is happening and why?
  2. How can I tweak this technique so it allows me to call this.superConstructor.call(this) and this.superPrototype.doStuff.call(this) as shown without hitting the infinite recursion on the immediate parent?

It works when I specify the super class in the calls as follows, but I would prefer not to have to do this:

function Child(){
    Parent.call(this);
}

Child.prototype.doStuff = function() {
    Parent.prototype.doStuff.call(this);
}

function Grandchild(){
    Child.call(this);
}

Grandchild.prototype.doStuff = function() {
    Child.prototype.doStuff.call(this);
}
3
  • 3
    In the Child function, this.superConstructor isn't Child's superConstructor when Child is called from Grandchild. Unfortunately, I am too sleep-deprived to provide a solution. Commented Mar 23, 2015 at 11:16
  • No, you cannot use .superConstructor or .superPrototype, it just doesn't work with them. Scrap them and use static references. Commented Mar 23, 2015 at 11:24
  • 1
    See also this and that Commented Mar 23, 2015 at 11:33

1 Answer 1

1

Okay. Here's the thing: In JS, this and new, together, are the single most confusing concept to grasp.

When you call new GrandChild(), what's this?

this is an object with its __proto__ set to the object pointed to by GrandChild.prototype. We will call this version of this, gc_this.

GrandChild() now executes this.superConstructor.call(this);. We can also say that it executes gc_this.superConstructor.call(gc_this);, because we theoretically renamed this within Grandchild() to gc_this.

The above execution calls Child() and has the same effect of executing new Child(). The only difference is that since we passed gc_this to it, it won't return anything and any and all this within Child() have been replaced with gc_this.

Okay, so far so good. No problems yet.

But now starts the problem: Since all this within Child() have been replaced with gc_this, the code within Child() has changed to:

function Child(){
    gc_this.superConstructor.call(gc_this);
}

This is the same exact line that we saw when we renamed this within GrandChild() to gc_this.

Therefore, this ends up in an infinite recursion.

And the only way to implement multi-level classical-inheritance in JS is to directly use the static class names, rather than relying on dynamically set custom properties.


If you want to gain some more insight on the topic, I recommend you have a look at: http://www.javascripttutorial.net/javascript-prototype/

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.