Can private properties be inherited?
1. Example: A Private Field on the Parent Is Not Accessible in the Subclass
class Parent {
#secret = "parent secret";
showSecret() {
console.log(this.#secret);
}
}
class Child extends Parent {
reveal() {
console.log(this.#secret); // Error
}
}
const c = new Child();
c.showSecret(); // "parent secret"
c.reveal(); // SyntaxError: Private field '#secret' must be declared in an enclosing classExplanation:
- The private field
#secret"belongs" only to theParentclass. - The
Childclass doesn't even know it exists. - So accessing
this.#secretinsideChildis impossible.
2. How This Works Under the Hood
When you declare #field, JavaScript creates a unique hidden identifier,
accessible only inside that class's body.
So even if you use the same name #secret in two classes,
these are two different fields, with no connection between them:
class Parent {
#secret = "parent";
getParentSecret() { return this.#secret; }
}
class Child extends Parent {
#secret = "child";
getChildSecret() { return this.#secret; }
}
const c = new Child();
console.log(c.getParentSecret()); // parent
console.log(c.getChildSecret()); // childHere, #secret on Parent and #secret on Child are two independent properties,
with the same name but different "hidden keys".
3. Why Private Fields Can't Be Inherited
This is a deliberate decision by the language's authors:
- To preserve strict encapsulation (everything starting with
#is fully hidden). - To avoid name conflicts between private properties of different classes.
- To simplify optimization in engines (V8, SpiderMonkey, etc.).
That's why extends inherits methods, but doesn't grant access to the parent's private fields.
4. So How Do You Share Private Data Between a Parent and a Subclass
If you want private data to be accessible in subclasses, use one of the following techniques:
Option 1: Use a Protected-Like Convention (_field)
This isn't real privacy, but it's often used in practice:
class Parent {
_secret = "accessible to subclasses";
showSecret() {
console.log(this._secret);
}
}
class Child extends Parent {
reveal() {
console.log(this._secret); // Works
}
}Here,
_secretis just a convention meaning "don't touch this property from outside". It's not protected, but it's accessible to subclasses.
Option 2: Use Getters / Setters
The parent can control access through methods, and the subclass can use those methods without knowing the implementation details.
class Parent {
#secret = "parent secret";
getSecret() {
return this.#secret;
}
}
class Child extends Parent {
reveal() {
console.log(this.getSecret()); // can be retrieved through the method
}
}
new Child().reveal(); // parent secretThis way, privacy is preserved, but access is still possible through an interface.
Option 3: Use a WeakMap (an Alternative to # Before ES2022)
This is an older but flexible way to have "private" data with controlled access.
const privates = new WeakMap();
class Parent {
constructor() {
privates.set(this, { secret: "shared secret" });
}
get _data() {
return privates.get(this);
}
}
class Child extends Parent {
reveal() {
console.log(this._data.secret); // accessible
}
}
new Child().reveal(); // shared secretA WeakMap lets you hide data while still making it accessible in subclasses.
5. Summary: Comparing the Approaches
| Approach | Privacy | Accessible to Subclasses | Real Protection |
|---|---|---|---|
#field | Full | No | Absolute |
_field (by convention) | Partial | Yes | No protection |
WeakMap | Almost full | Yes | Yes |
| Getter/setter | Through an interface | Yes | Controlled |
Brief Conclusion
Private fields (
#field) are not inherited. Each class has its own private space. Subclasses cannot access the parent's private fields directly. If you need to share private data, use:
_field(a convention),- getters/setters,
- or a
WeakMapwith access for subclasses.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.