Search code examples
javascriptobjectextending

Javascript "extending" a method in a sub-object or subclass


My goal is to have a widget object and have specific widgets extend that object. I would like to prevent people from having to call the render callback explicitly in every widget definition by somehow extending it in the parent (Widget). What is the best way to accomplish this?

 var Widget = function (options) {

    // super class

    if (this.constructor === Widget) {
        throw new Error("You can't instantiate abstract class.");
    }

    var widget = this.__proto__;

    Widget.renderCallBack = function(){
        //alert('the widget has rendered');
    }

    this.render = (function(){
        var _render = this.render;

        return function(){
            _render();
            Widget.renderCallBack();
        }

    })


}
Widget.constructor = Widget;


var SpecialWidget = function(options) {
    Widget.apply(this, arguments);
}

SpecialWidget.prototype = Object.create(Widget);
SpecialWidget.constructor = SpecialWidget

SpecialWidget.prototype.render = function(){
    // render something
}

new SpecialWidget(options);

Solution

  • In addition to my comment: If it is the same for all it doesn't have to be a callback function, just put the code to the end of the render method if it's job is synchronous, if not use a promise but you have to think about that of method shadowing you will overwrite the parent class' render method in the child. To avoid this you can use different name for the methods and call the parent's method from the child or use ES2015 class which has the super keyword for reaching the parent class' methods.

    Also you had a typo in your code:

    SpecialWidget.prototype = Object.create(Widget);
    

    It has to be:

    SpecialWidget.prototype = Object.create(Widget.prototype);
    

    Anyway I don't think it is a good idea in general.

    var Widget = function(options) {
      this.options = options || {};
    };
    
    Widget.prototype.widgetRender = function() {
      // do stuff
      console.log('Widget render');
      // callback functionality
      console.log('Widget render callback functionality');
    };
    Widget.constructor = Widget;
    
    
    var SpecialWidget = function(options) {
      Widget.apply(this, arguments);
    };
    
    SpecialWidget.prototype = Object.create(Widget.prototype);
    SpecialWidget.prototype.render = function() {
      // parent's render
      this.widgetRender();
      // do stuff
      console.log('SpecialWidget render');
      // callback functionality
      console.log('SpecialWidget render callback functionality');
    };
    SpecialWidget.constructor = SpecialWidget
    
    var sw = new SpecialWidget();
    sw.render();
    
    // ES2015
    
    class ES6Widget {
      constructor(options) {
        this.options = options || {};
      }
      render() {
        // do stuff
        console.log('ES6Widget render');
        // callback functionality
        console.log('ES6Widget render callback functionality');
      }
    }
    
    class ES6SpecialWidget extends ES6Widget {
      render() {
        // parent's render
        super.render();
        // do stuff
        console.log('ES6SpecialWidget render');
        // callback functionality
        console.log('ES6SpecialWidget render callback functionality');
      }
    }
    
    
    const es6sw = new ES6SpecialWidget();
    es6sw.render();