In other words, why isn’t DOMException like AggregateError, EvalError, etc?
Both expressions evaluate to true:
Object.getPrototypeOf(DOMException) === Function.prototype
Object.getPrototypeOf(DOMException.prototype) === Error.prototype
I used to think the following generalization has no counterexamples:
If
- X and Y are constructor functions, and
- Y is not the Object() constructor, and
- X.prototype has Y.prototype as its [[Prototype]] object
Then - X has Y as its [[Prototype]] object
For example, the above generalization holds for the following X,Y pairs
- HTMLElement, Element
- AggregateError, Error
- AsyncFunction, Function
- Node, EventTarget
- Element, Node
- RTCError, DOMException
The only case I know of in which the generalization fails is when X = DOMException and Y = Error.
Is there a deeper reason why the DOMException constructor itself cannot have the Error constructor as its [[Prototype]]?
2
Answers
No, that is not a valid generalisation. It’s common, but not ubiquituous. This pattern only started to appear since ES6
class
es introduced the inheritance ofstatic
properties (including methods in particular) via the prototype chain. Until then, constructor functions were just plain functions, which inherited fromFunction.prototype
. Many libraries still do this.However, it’s true that this generalisation holds for nearly all builtin classes, both native ones (defined by ECMAScript) and host-provided ones (like the DOM). For the
Error
hierarchy this was consciously introduced with ES6, in ES5.1 the native error constructors had still inherited fromFunction.prototype
.For Web APIs, the Web IDL specification prescribes just this pattern for its interfaces:
constructorProto
berealm
.[[Intrinsics]].[[%Function.prototype%]].I
inherits from some other interfaceP
, then setconstructorProto
to the interface object ofP
in realm.and
interface
is declared to inherit from another interface, then setproto
to the interface prototype object in realm of that inherited interface.proto
torealm
.[[Intrinsics]].[[%Object.prototype%]].Looking at those rules, there’s actually a second exception: the
Window
constructor inherits fromEventTarget
, but theWindow.prototype
inherits from aWindowProperties
object (which in turn inherits fromEventTarget.prototype
).No. There’s a few likely explanations though:
DOMException
was part of the first browser js implementations alreadynobody bothered to update itit’s just an oversightEdit: Actually Web IDL explicitly describes it as an exception to the rule. It does not
inherit
fromError
, but it still "has its [[Prototype]] internal slot set to the intrinsic object%Error.prototype%
". This was discussed in issue #55 and changed in PR #378 to align with the implementation reality – away from the previously described [[Prototype]] value of%Error%
.Any constructor is inherited from
Function
because it’s just a function and has nothing to do with its function’s prototype: