Evaluating a class expression that captures nothing twice returns the same constructor. A property defined on the second evaluation's prototype is therefore visible to instances of the first.
function makeClass() { return class { constructor() {} }; }
const K1 = makeClass(), K2 = makeClass(); let seen = -1;
Object.defineProperty(K2.prototype, "k", { set(v: number) { seen = v; }, configurable: true });
const o: any = new K1(); o.k = 4;
console.log(seen, Object.prototype.hasOwnProperty.call(o, "k"), K1 === K2, Object.getPrototypeOf(o) === K2.prototype);
| runtime |
output |
| node |
-1 true false false |
| perry main |
4 false true true |
Every evaluation of a class expression must produce a distinct constructor and a distinct prototype (ClassDefinitionEvaluation). The capture-free case lowers to one shared template class. PR #11297 makes classes that capture something distinct per evaluation, but it does not cover this case: a class with no captures never enters that path.
Found by the inherited-access lane while testing prototype-in-shape.
Evaluating a class expression that captures nothing twice returns the same constructor. A property defined on the second evaluation's prototype is therefore visible to instances of the first.
-1 true false false4 false true trueEvery evaluation of a class expression must produce a distinct constructor and a distinct prototype (ClassDefinitionEvaluation). The capture-free case lowers to one shared template class. PR #11297 makes classes that capture something distinct per evaluation, but it does not cover this case: a class with no captures never enters that path.
Found by the inherited-access lane while testing prototype-in-shape.