开发者

Javascript inheritance and method overriding

Assume I have a class like this:

function Widget() {
    this.id = new Date().getTime();
    // other fields
}
Widget.prototype = {
    load: fun开发者_C百科ction(args) {
        // do something
    }
}

From this class I created some other classes which inherit the same prototype but have some added methods. What I want to do is being able to define a load() method in the sub-classes which first calls the parent method and then execute some code. Something like:

SpecialWidget.prototype = {
    load: function(args) {
        super.load(args);
        // specific code here
    }
}

I know there's no super keyword in Javascript but there must be a way to do this.


You can simulate it like this:

SpecialWidget.prototype = {
    load: function(args) {
        Widget.prototype.load.call(this, args);
        // specific code here
    }
}

Or you can create your own super property like this:

SpecialWidget.prototype.parent = Widget.prototype;

SpecialWidget.prototype = {
    load: function(args) {
        this.parent.load.call(this,args);
        // specific code here
    }
}


so first, you set up your 'subclass' like so

function SubClass(name) {
    Super.call(this);

    // stuff here
}

SubClass.prototype = new SuperClass(null);
SubClass.prototype.constructor = SubClass;

and then you can do

SuperClass.prototype.theMethod.apply(this);

from within a subclass implementation to specifically invoke the super's implementation.


I don't know if this is the best solution, but you could do something like this:

function Widget() {
    this.id = new Date().getTime();
}
Widget.prototype.load = function(args) {
   alert( 'parent load' );
};

SpecialWidget = function(){};

   // Make the prototype of SpecialWidget an instance of Widget
var proto = SpecialWidget.prototype = new Widget;

   // Give the prototype a function that references the "load" from Widget
proto.parent_load = proto.load;

   // Give SpecialWidget its own "load" that first calls the parent_load
proto.load = function( args ) {
    this.parent_load( args );
    alert( 'special load' );
};

var inst = new SpecialWidget;

inst.load();

This makes the prototype of SpecialWidget an instance of Widget so that it inherits all that Widget has.

Then it makes a reference to the load() of Widget called parent_load(), and creates its own load() that calls the parent_load() when invoked.


Since mid-2015 (ECMAScript 2015), javascript has Classes and super

Here's the link: https://262.ecma-international.org/6.0/, see section 12.3.5 (super) and 14.5 (Class definitions).

How your code would look with those changes:

class Widget() {
    constructor() {
        this.id = new Date().getTime();
        // other fields
    }
    load(args) {
        // do something
    }
}

class SpecialWidget extends Widget {
    load(args) {
        super.load(args);
        // specific code here
    }
}

The closest I got to the previous syntax (without using class but using super) was using Object.setPrototypeOf:

// UNCHANGED
function Widget() {
    this.id = new Date().getTime();
    // other fields
}
Widget.prototype = {
    load: function(args) {
        // do something
    }
}

// slightly changed to declare SpecialWidget
function SpecialWidget() {}

// changed to define load as an method, and not a property with function as value
SpecialWidget.prototype = {
    load(args) {
        super.load(args);
        // specific code here
    }
}

// here's the key
Object.setPrototypeOf(SpecialWidget.prototype, Widget.prototype);

The declaration of load was changed because super can be used inside methods, but not functions. So, instead of load: function(args) { body }, it's simply load(args) { body }.

But, there's a caveat: with this solution, elements of SpecialWidget will not inherit the id defined as new Date().getTime(). I don't think there's a workahound (without using classes or duplicating code declaring this.id inside SpecialWidget).


It would be possible to store the old value of the load method in a closure, if you did your overriding like this:

function Widget() {
    this.id = new Date().getTime();
    // other fields
}

Widget.prototype = {
    load: function(args) {
        // do something
        alert("Widget Prototype Load");
    }
};

function SpecialWidget(){
};

SpecialWidget.prototype = new Widget();

(function(){
    var oldLoad = SpecialWidget.prototype.load;
    SpecialWidget.prototype.load = function(){
        oldLoad();
        alert("new Load");
    };
}());


var x = new SpecialWidget();
x.load();

It works, but I'm not sure if it's the best method.


Using Simple Javascript Class:

Class.extend('Widget', {
  load: function () {
    alert('foo');
  }
});

Widget.extend('SpecialWidget', {
  load: function () {
    this.super();
    alert('bar');
  }
});

new Widget().load(); // Alert: 'foo'
new SpecialWidget().load(); // Alert: 'foo' and 'bar'

Take a look at Simple Javascript Class Project, Simple JavaScript Inheritance and Inheritance Patterns in JavaScript.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜