How to properly subclass a subclass in JavaScript?

2019-06-13 08:12发布

I thought I had a good understanding on how to properly extend classes in JavaScript, but when extending a subclass I run into an endless loop when I override a method, and the call the parent method from the child class. I'm either doing it wrong, or you just shouldn't subclass this way in JavaScript.

Can anybody help educate me please?

var Grand = function() {
	this.test();
};

Grand.prototype.constructor = Grand;

Grand.prototype.test = function() { 
	console.log( "Grand!")
};



var Parent = function() {
  this.supr.constructor.call( this );
};

Parent.prototype = Object.create( Grand.prototype );
Parent.prototype.constructor = Parent;
Parent.prototype.supr = Grand.prototype;

Parent.prototype.test = function() { 
	this.supr.test.call( this );
  console.log( "Parent!" );
};



var Child = function() {
  this.supr.constructor.call( this );
};

Child.prototype = Object.create( Parent.prototype );
Child.prototype.constructor = Child;
Child.prototype.supr = Parent.prototype;

Child.prototype.test = function() { 
	this.supr.test.call( this );
  console.log( "Child!" );
};



var g = new Grand(); // Outputs "Grand!"
var p = new Parent(); // Outputs "Grand!" "Parent!"
var c = new Child(); // Error: Endless Loop!

I would expect the console to log "Grand!", "Parent!", "Child!" when instantiated a new Child(), but instead I get an endless loop.

I'm coming from an ActionScript background, so creating classes in JavaScript still throws me some curve balls. Thanks for the help in advance!

2条回答
兄弟一词,经得起流年.
2楼-- · 2019-06-13 08:24

The problem is with this bit of code:

var Parent = function() {
  this.supr.constructor.call( this );  
};

Consider what happens when this code executes:

var c = new Child();

Here this is the variable c, so this.supr.constructor will always be the parent's constructor as setup in these lines of code:

Child.prototype.supr = Parent.prototype;  // i.e. this.supr = Parent.prototype
Parent.prototype.constructor = Parent;  // i.e. this.supr.constructor = Parent

So, when the Child's constructor invokes this.supr.constructor.call( this ); it executes the Parent function, and the parent function again executes this.supr.constructor.call( this ); resulting the Parent function being invoked again, causing the endless loop.

A fix is to invoke base class functions as follows:

var Child = function() {
  Child.prototype.supr.constructor.call( this );
};

More details in this post

查看更多
SAY GOODBYE
3楼-- · 2019-06-13 08:35

I recommend switching to es6. This prototyping can be a real mess and is harder to keep track of. But then if you need this in the browser, you should transpile your code to es5 whit babel or such. In the Node env its fine without as long as you have a recent up to date version. Some of the latest browser supports it as well

class Grand {
    constructor() {
        this.test()
    }

    test() {
        console.log( "Grand!")
    }
}

class Parent extends Grand {
    test() {
        super.test()
        console.log( "Parent!" )
    }
}

class Child extends Parent {
    test() {
        super.test()
        console.log( "Child!" )
    }
}

let g = new Grand(); // Outputs "Grand!"
let p = new Parent(); // Outputs "Grand!" "Parent!"
let c = new Child(); // Outputs "Grand!" "Parent! "child!"

Not only is it more readable, but it's less code and more understandable

查看更多
登录 后发表回答