Search code examples
javascriptprototypal-inheritance

Extend function does not call the base constructor


I have a component system that should extend from a base object called component.

New components can be registered via a function called registerComponent(). This function takes one parameter - the child class - and should inject the parent class component into it.

The following code almost handles this scenario, with the problem, that the component constructor is never called:

// Base component.
function component() { 
  this.visible = false; 
  console.log('Construct component.'); 
}
component.prototype.isVisible = function() { 
  console.log('visibility:', this.visible); 
}

// Custom component that will be extended in a moment.
function button() { 
  this.caption = 'button'; 
  console.log('Construct button.'); 
}

// This is the function I need help with:
function registerComponent(obj) {
  function dynamicComponent() { 
    component.call(this); 
    obj.call(this);
  }

  dynamicComponent.prototype = Object.create(component.prototype);
  obj.prototype = Object.create(dynamicComponent.prototype);
  obj.prototype.constructor = obj;
}

// Now we register the button, which should add two things: 
// the property "this.visible"
// the method "this.isVisible()"
registerComponent(button);

// The test:
b = new button(); // Output is "Construct button."
                  // but not "Construct component." 
b.isVisible();    // Output is "visibility: undefined"

In the above code the method component.prototype.isVisible() is correctly injected into the button. However, the constructor is not called, and therefore the property this.visible is undefined, instead of false.

What am I missing here?


Solution

  • I think you're looking for

    // This is the function I need help with:
    function registerComponent(obj) {
      function dynamicComponent() { 
        component.call(this); 
        obj.call(this);
      }
    
      obj.prototype = dynamicComponent.prototype = Object.create(component.prototype);
      obj.prototype.constructor = dynamicComponent;
    
      return dynamicComponent;
    }
    
    const button = registerComponent(function() { 
      this.caption = 'button'; 
      console.log('Construct button.'); 
    });
    
    const b = new button();
    

    You cannot alter an existing button function to make it implicitly call component.