When I run this code:
'use strict';
class Base {
constructor() {
this._public();
}
}
class Child extends Base {
constructor() {
super();
}
_public() {
this.#privateMethod();
}
#privateMethod() {
this.bar = 1234;
}
}
const c = new Child();
console.log(c.bar);
I get the following error:
this.#privateMethod();
^
TypeError: Receiver must be an instance of class Child
As I understand JavaScript, the receiver in the following code is exactly an instance of the class Child. It's even shown in the dev tools inspector:
So could someone please explain to me what's going on? Is it a bug or what?
Actually FF shows a more accurate error message:
Uncaught TypeError: can't access private field or method: object is not the right class
This is one example of why it's best not to call public instance methods from constructors. When your Base
class constructor calls this._public()
, Child
's initialization is not (yet) complete. The earliest you can use Child
members is after super()
has returned, not before. It's only after super()
returns that Child
's automatic initialization (such as setting up private fields and methods, and initializing public properties defined via class fields syntax) is complete. You can see this with public class fields as well:
class Base {
constructor() {
console.log("test" in this); // false
}
}
class Child extends Base {
test; // <== Public class field
constructor() {
super();
console.log("test" in this); // true
}
}
new Child();
You're okay to call this._public()
from Child
's constructor just after super()
returns (although, again, it's best not to call public methods from constructors! better to call #privateMethod
directly), because Child
will be fully ready by then (other than any initialization you're doing in its constructor, of course), but not before super()
returns.