2

Hello,

I'm trying to do something with function.prototype.call to ensure a dynamic inheritance.

Here's a basic example what I'm trying to do:

class Person {
  constructor(name, test) {
    this.name = name;
    this.test = test;
  }
}
class Police {
  constructor(name, badge, ...manyArgs) {
    //Attempt 1:
    Person.call(this, name, 'hello world');
    //I also tried:
    Person.constructor.call(this, name, 'hello world');

    console.log(this.test); //This should print a log message of 'hello world'
  }
}

The first attempt doesn't work because a class is not a function, and only functions have the call method in their prototype. The second attempt doesn't give an error, but just doesn't inherit the test value set in Person.

Something that does work is if I would change the Person class to:

function Person(name, test) {
  this.name = name;
  this.test = test;
}

But unfortunately I don't have the luxery to change the class' code that I'm trying to inherit like this.

I've searched online a lot, but couldn't find why the call function wouldn't work for class-based classes. It's confusing for me because you can easily rewrite class-based classes to function-based classes.

Does anyone have an idea of how to use the prototype.call method to inherit a class?

DutchJelly
  • 116
  • 9
  • 1
    Generally you'll use `extends` to inherit, but if it needs to be dynamic, then there is [`Reflect.construct()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/construct) (which will return a new object) – Nick Parsons Dec 05 '21 at 23:42
  • It's not clear what you mean by "*dynamic inheritance*". Why not simply write `class Officer extends Person` and use `super` as normal? – Bergi Dec 05 '21 at 23:43
  • 1
    possible duplicate of [Is it possible to inherit old-style class from ECMAScript 6 class in JavaScript?](https://stackoverflow.com/q/33369131/1048572) (but it's really weird you're trying to do this inside of a `class`, not inside of a `function`) – Bergi Dec 05 '21 at 23:44
  • I'm trying to inherit from a class that I pass in the constructor, because I have to work with requireJS want to avoid nesting the class. So I guess I could find a workaround pretty easily, but I was just intrigued and curious why this `call`-method didn't work. – DutchJelly Dec 05 '21 at 23:47
  • 1
    What do you mean by "*avoid nesting the class*"? It would help if you could share your actual code. And what do you expect the prototype chain to look like if you're passing different "parent classes" to your "constructor"? At that point, I think you just have a factory function with dependency injection, and should simply instantiate the class using `new`, not doing any sort of "inheritance". – Bergi Dec 05 '21 at 23:51
  • I'm requiring a GraphicsLayer class that I want to extend in my own class, but requireJS works with nested callbacks which I don't like. The reason I want to do this, is because I don't want to change the code too much so it's more similar to similar projects. However, you're right, I should probably just go for the easy solution and use extends or just return the parent object somewhere. – DutchJelly Dec 05 '21 at 23:54
  • 1
    I guess the solution to that would be not using requirejs (or at least not writing the amd module format by hand): use ES6 modules and a transpiler! – Bergi Dec 06 '21 at 00:13

1 Answers1

1

Class constructors in JavaScript can only be called with new, Reflect.construct orsuper in a class extension. This tightens up and standardizes alternatives construction techniques using ordinary function objects.

Although class objects are functions and do inherit a call method, attempting to use className.call(...) will generate an error similar to

TypeError: class constructors must be invoked with 'new'

First answer: as a result of the above you will not be able to call the constructor of a class using `Function.prototype.call'.


As mentioned in comments, extending a base class is an alternative to creating a constructor function, but when written as a class declaration doesn't provide dynamic inheritance.

However this dosn't prevent you dynamically extending a class expression written inside a factory function. As an example:

class Person {
  constructor(name, test) {
    this.name = name;
    this.test = test;
  }
}

// factory function:

function policeExtend(baseClass) {

    return class Police extends baseClass {
      constructor(name, badge) {
        super(name, "'just testing'");
        this.badge = badge;
      }
    };
}

const PolicePerson = policeExtend(Person);

let officer = new PolicePerson("chief", 100);
console.log( officer.name, officer.badge, officer.test)
traktor
  • 17,588
  • 4
  • 32
  • 53