Split out from #10556 while fixing new Sub() instanceof EventEmitter (PR #10592, root cause and
fix there). instanceof for a native-builtin subclass now walks the registered class-chain parent
edge, but the subclass's declared prototype object is still not identity-linked to the builtin's real
.prototype object.
Reproduction
import { EventEmitter } from "node:events";
class Sub extends EventEmitter {}
console.log(Object.getPrototypeOf(Sub.prototype) === EventEmitter.prototype);
console.log(typeof EventEmitter.prototype);
Expected (Node 26.5.1)
Actual (Perry, v0.5.1592 + PR #10592)
typeof EventEmitter.prototype does not throw and reads as "object", matching Node — so this is
narrower than "accessing EventEmitter.prototype throws"; it is specifically that
Object.getPrototypeOf(Sub.prototype) does not return the same object identity as
EventEmitter.prototype. instanceof, util.inherits-based prototype linking, and the class-chain
walk (all fixed by #10592) do not depend on this identity and are unaffected.
Suspected area
Native-base-class subclassing (see CLAUDE.md "Known-weak areas: Native base-class subclassing" — a
native base's surface is installed at super() time and its parent edge lives in the class registry,
which is a different mechanism than declared-class prototype-object identity). Likely needs
Sub.prototype's [[Prototype]] to be set to the actual EventEmitter.prototype object at class
construction time for natively-backed builtins, not just a reserved class id for the instanceof
chain walk.
Impact
Low — spec-compliance gap for prototype introspection / mixin patterns that compare
Object.getPrototypeOf identity directly, rather than using instanceof. Not currently known to break
a specific npm package.
Split out from #10556 while fixing
new Sub() instanceof EventEmitter(PR #10592, root cause andfix there).
instanceoffor a native-builtin subclass now walks the registered class-chain parentedge, but the subclass's declared prototype object is still not identity-linked to the builtin's real
.prototypeobject.Reproduction
Expected (Node 26.5.1)
Actual (Perry, v0.5.1592 + PR #10592)
typeof EventEmitter.prototypedoes not throw and reads as"object", matching Node — so this isnarrower than "accessing
EventEmitter.prototypethrows"; it is specifically thatObject.getPrototypeOf(Sub.prototype)does not return the same object identity asEventEmitter.prototype.instanceof,util.inherits-based prototype linking, and the class-chainwalk (all fixed by #10592) do not depend on this identity and are unaffected.
Suspected area
Native-base-class subclassing (see CLAUDE.md "Known-weak areas: Native base-class subclassing" — a
native base's surface is installed at
super()time and its parent edge lives in the class registry,which is a different mechanism than declared-class prototype-object identity). Likely needs
Sub.prototype's[[Prototype]]to be set to the actualEventEmitter.prototypeobject at classconstruction time for natively-backed builtins, not just a reserved class id for the
instanceofchain walk.
Impact
Low — spec-compliance gap for prototype introspection / mixin patterns that compare
Object.getPrototypeOfidentity directly, rather than usinginstanceof. Not currently known to breaka specific npm package.