Setting properties of super
, such as super.x = 1
, behaves like Reflect.set(Object.getPrototypeOf(objectLiteral), "x", 1, this)
. This is one of the cases where understanding super
as simply "reference of the prototype object" falls short, because it actually sets the property on this
instead.
class A {}
class B extends A {
setX() {
super.x = 1;
}
}
const b = new B();
b.setX();
console.log(b); // B { x: 1 }
console.log(Object.hasOwn(b, "x")); // true
super.x = 1
will look for the property descriptor of x
on A.prototype
(and invoke the setters defined there), but the this
value will be set to this
, which is b
in this context. You can read Reflect.set
for more details on the case when target
and receiver
differ.
This means that while methods that get super.prop
are usually not susceptible to changes in the this
context, those that set super.prop
are.
/* Reusing same declarations as above */
const b2 = new B();
b2.setX.call(null); // TypeError: Cannot assign to read only property 'x' of object 'null'
However, super.x = 1
still consults the property descriptor of the prototype object, which means you cannot rewrite non-writable properties, and setters will be invoked.
class X {
constructor() {
// Create a non-writable property
Object.defineProperty(this, "prop", {
configurable: true,
writable: false,
value: 1,
});
}
}
class Y extends X {
constructor() {
super();
}
foo() {
super.prop = 2; // Cannot overwrite the value.
}
}
const y = new Y();
y.foo(); // TypeError: "prop" is read-only
console.log(y.prop); // 1