toddmo toddmo - 2 months ago 7
Javascript Question

How to use base class methods in a subclass of a Builtin JavaScript class in javascript

In c# for example I can extend a framework type and assign an expression to my type and it will retain all the members of the base type but also have my extended methods.

I'm trying to inherit

Sentence
from
Range
.

Note the suggested duplicate doesn't apply here because
Range
is not susceptible to these techniques.

How can I achieve this in javascript? I have:



/* Namespace */
var WebPageReader = WebPageReader || {};

/* Classes */
WebPageReader.Sentence = function(range) {
this.setStart(range.startContainer, range.startOffset); // bombs here
this.setEnd(range.endContainer, range.endOffset);
};

function test(){
WebPageReader.Sentence.prototype = new Range();
var dom = new WebPageReader.Dom();
var s = new WebPageReader.Sentence(dom.GetSelectedRange());
alert(s.endOffset) ;
}
WebPageReader.Dom = function() {

/* public methods */
this.GetSelectedRange = function() {
var sel;
if (window.getSelection) {
sel = window.getSelection();
if ((sel.type == "Range" || allowCaretSelection) && sel.rangeCount) {
return sel.getRangeAt(0);
}
}
return null;
}
}


This gives the error:


Uncaught TypeError: Illegal invocation


Attempt #2

When i change my code to this:

/* Namespace */
var WebPageReader = WebPageReader || {};

/* Classes */
WebPageReader.Sentence = function(range) {
Range.call(this);
};

function test(){
WebPageReader.Sentence.prototype = new Range();
var dom = new WebPageReader.Dom();
var s = new WebPageReader.Sentence(dom.GetSelectedRange());
alert(s.endOffset) ;
}


I get this error


Uncaught TypeError: Failed to construct 'Range': Please use the 'new'
operator, this DOM object constructor cannot be called as a function.

Answer

You are not subclassing properly. You should use ES6 classes.

var WebPageReader = {
  Dom: function() {
    this.GetSelectedRange = function() {
      if (!window.getSelection) return null;
      return window.getSelection().getRangeAt(0);
    }
  },
  Sentence: class extends Range {
    constructor(range) {
      super();
      this.setStart(range.startContainer, range.startOffset);
      this.setEnd(range.endContainer, range.endOffset);
    }
  }
};
document.body.addEventListener('click', function() {
  var dom = new WebPageReader.Dom();
  var s = new WebPageReader.Sentence(dom.GetSelectedRange());
  console.log(s.endOffset);
});
Select text

It works because super() initializes the instance as a real Range. In ES5 you can only do things like making the instance inherit from Range.prototype, which is not enough to be a real Range instance. And Range methods can only be called on real Range instances.