2

It seems you cannot call a superclass arrow function using super.methodName() within a subclass:

class Parent {
  constructor() {
    console.log('in `Parent` constructor')
  }
  parentArrow = () => {
    console.log('parentArrowFn')
  }
  parentMethod() {
    console.log('parentMethod')
  }
}

class Child extends Parent {
  constructor() {
    super()
    console.log('in `Child` constructor')
  }
  childMethod() {
    console.log('childMethod')
    super.parentMethod() // works
    super.parentArrow() // Error
  }
}

(new Child()).childMethod();

Generates the error:

Uncaught TypeError: (intermediate value).parentArrow is not a function
    at Child.childMethod (<anonymous>:21:15)
    at <anonymous>:1:7

Is there any way to prevent this so that I can use arrow functions in my parent class, yet ensure they are accessible via super in subclasses?

Barmar
  • 741,623
  • 53
  • 500
  • 612
1252748
  • 14,597
  • 32
  • 109
  • 229
  • Do you have to use `super` or is `this` also an option? (It works with `this`) – Wendelin Aug 19 '19 at 17:34
  • Why do you need `super` here? Both of these examples work properly if you use `this.` instead. – loganfsmyth Aug 19 '19 at 17:34
  • 3
    Also, it's unusual to use arrow functions for methods, because they won't be able to use `this`. – Barmar Aug 19 '19 at 17:37
  • @KevinB I'm don't know about that. If it was and that has been sufficiently answered, maybe mark it as a duplicate? – 1252748 Aug 19 '19 at 17:47
  • @Barmar I use arrow functions with transform-class-properties plugin to avoid having to bind methods in constructor in react classes. I thought this was pretty common, no? – 1252748 Aug 19 '19 at 17:51
  • @Barmar I agree https://stackoverflow.com/questions/57559267/why-cant-javascript-es6-call-an-anonymous-super-function seems similar, but there aren't better answers there. – 1252748 Aug 19 '19 at 18:01
  • You think the answers here are better? I could reverse the duplicate link. – Barmar Aug 19 '19 at 18:02
  • @barmar wrong! `this` points to the instance inside arrow functions inside class fields. (but good dupe ;)) – Jonas Wilms Aug 19 '19 at 18:02
  • @1252748 the only answer here is technically wrong ... – Jonas Wilms Aug 19 '19 at 18:03
  • To answer your question: You just cannot. You cannot refer to properties of the instance via `super`. Also you can't have two properties with the same name – Jonas Wilms Aug 19 '19 at 18:05
  • @JonasWilms Are "class fields" something new and special? I was just talking about ordinary object properties. Arrow functions don't get their context from the call site, they get it from the definition site. – Barmar Aug 19 '19 at 18:06
  • @barmar yes, "class fields" are a stage 3 proposal. `class Test { field = value }` is roughly equal to `class Test { constructor() { this._init(); } _init() { this.field = value }}`, so in other words: (1) initialized before the constructors body gets run, (2) `this`and `super` work the way they would in a regular method, just that arrow functions initialized there get bound – Jonas Wilms Aug 19 '19 at 18:08

1 Answers1

4

Public fields or "class instance fields" in es6 classes are not yet supported natively in all environments and even if it is you need to call it through a this reference instead of super as it becomes an instance property rather than a property on the prototype:

class Parent {
  constructor() {
    console.log('in `Parent` constructor')
  }   
  parentArrow = () => {
      console.log('parentArrowFn')
  }
  parentMethod() {
    console.log('parentMethod')
  }
}

class Child extends Parent {
  constructor() {
    super()
    console.log('in `Child` constructor')
  }
  childMethod() {
    console.log('childMethod')
    super.parentMethod() // works
    this.parentArrow() // Calls parentArrow 
  } 
}
new Child().childMethod();

The need to call the arrow function using this instead of super is because when using an arrow function as a method the parentArrow is added as a property of the instance rather than of the prototype and super is used for calling methods declared on the prototype.

Your code can be translated to the code below, when you declare an arrow function inside a class:

constructor() {
   console.log('in `Parent` constructor');
   // becomes an instance property
   this.parentArrow = () => { <----
     console.log('parentArrowFn') |
   }                              |
}                                 |
parentArrow = () => {          ----
   console.log('parentArrowFn')
}
Fullstack Guy
  • 16,368
  • 3
  • 29
  • 44
  • 3
    *as the parentArrow property is not defined until the Child constructor is not finished completely.* wrong! According to the proposal, class fields are run before the code in the constructor runs. Also this is not a timing issue, as childMethod is called after construction was finished – Jonas Wilms Aug 19 '19 at 18:01
  • @JonasWilms rephrased and corrected my answer. – Fullstack Guy Aug 19 '19 at 18:15