Javascript 是否存在所有DOM接口之间继承关系的表示?

Javascript 是否存在所有DOM接口之间继承关系的表示?,javascript,html,inheritance,dom,webapi,Javascript,Html,Inheritance,Dom,Webapi,当我阅读其中一篇文章时,我看到下面有一个类似SVG的东西,其中对象接口指向它继承的另一个: 工具 您可以使用一些JavaScript方法自己创建此树。 在这种方法中,我将使用很多,因为它允许我们轻松地将任意值映射到彼此(即,键不仅仅是字符串和符号,就像在对象中一样),以及 获取原型 构造函数的prototype属性在使用时始终映射到超类的原型。 看看这些关系: Object.getPrototypeOf(Node.prototype)==EventTarget.prototype//Event

当我阅读其中一篇文章时,我看到下面有一个类似SVG的东西,其中对象接口指向它继承的另一个:

工具 您可以使用一些JavaScript方法自己创建此树。 在这种方法中,我将使用很多,因为它允许我们轻松地将任意值映射到彼此(即,键不仅仅是字符串和符号,就像在对象中一样),以及

获取原型 构造函数的
prototype
属性在使用时始终映射到超类的原型。 看看这些关系:

Object.getPrototypeOf(Node.prototype)==EventTarget.prototype//EventTarget是节点的超类。
Object.getPrototypeOf(Node)==EventTarget//EventTarget是节点的超类。
Object.getPrototypeOf(EventTarget.prototype)==Object.prototype//Object是EventTarget的超类。
Object.getPrototypeOf(EventTarget)==Function.prototype//Function不是EventTarget的超类;这只是构造函数的基本情况,它是一个函数。
Object.getPrototypeOf(Object.prototype)==null//对象不从任何对象继承。
Object.getPrototypeOf(Object)==Function.prototype//同样,这里只显示函数,因为构造函数是它的一个实例。
这适用于所有内置的和主机定义的构造函数,除非它是构造函数,但没有
prototype
属性。 我不确定代理是否从任何东西继承,如果是,从什么继承。 我们暂时不谈了

无论如何,在这里使用
.prototype
更直观一些

获得所有课程 获取所有构造函数是可能的,因为大多数内置和主机定义的构造函数都是全局的,只有
TypedArray
例外。 使用将生成所有全局属性及其描述符。 (在web上,可以使用
窗口
代替
全局此
,在节点上,它是
全局

描述符包含一些设置,例如,如果可以在的–循环中的中看到属性,等等。 如果属性是一个getter/setter对,您将看到相应的
get
set
函数。 任何普通属性都有一个
描述符。 没有构造函数是getter/setter对,因此必须存在
,因为所有构造函数都是全局属性,所以我们要寻找函数。 如前所述,这些构造函数必须具有
prototype
属性,或者是
Proxy

Object.entries(Object.getOwnPropertyDescriptors(globalThis))
.filter(([|,{value}])=>value==Proxy | | typeof value===“函数”和&value.hasOwnProperty(“原型”))
这将获得所有构造函数的列表,但是由于
Proxy
是一种特殊情况,并且
对象
有一个讨厌的
null
原型要处理,所以让我们实际地过滤掉它们并手动处理它们

const allConstructors=Object.entries(Object.getOwnPropertyDescriptors(globalThis))
.filter(([[uu,{value}])=>value!==Object&&typeof value===“函数”&&value.hasOwnProperty(“原型”);
生成树 我们将初始化三个
Map
s:

  • classInheritanceTree
    是具有继承结构的树
  • classInheritanceReferences
    是一个平面结构,将每个构造函数映射到
    classInheritanceTree
    中的引用
  • constructorNames
    将每个构造函数映射到与其关联的任何名称
const classInheritanceTree=新映射([
[
无效的
新地图([
[
对象
新地图()
]
])
],
]),
classInheritanceReferences=新地图([
[null,classInheritanceTree.get(null)],
[对象,classInheritanceTree.get(null).get(对象)]
]),
constructorNames=新地图([
[
无效的
新集([
“空”
])
],
[
对象
新集([
“对象”
])
]
]);
当然,
null
实际上不是继承树的一部分,但是为了可视化的目的,它充当了一个有用的树根。 请注意,
.constructor.name
并不总是与
globalThis
上的属性名称匹配,例如在Firefox 90中:
webkitURL.name==“URL”
webkitcsmatrix.name==“DOMMatrix”
,以及
webkitURL==URL
webkitcsmatrix==DOMMatrix
。 这就是为什么
constructorNames
的值是包含所有别名的
Set
s

我们通过迭代所有构造函数并确定其原型的
构造函数来同时填充所有三个映射。
populateInheritanceTree
函数的自调用仅确保在将其子类放入结构之前,所有
Map
中都存在一个超类。
classInheritanceTree
仅在填充
classInheritanceReferences
时隐式填充:后者包含对前一个中的
Map
s的引用,因此通过更新一个,我们也会对另一个进行变异

allConstructors.forEach(函数populateInheritanceTree([name,{value}])){
const superClass=Object.getPrototypeOf(value.prototype).constructor;
//确保“classInheritanceReferences”中包含该超类;
//使用与超类对应的参数调用函数本身。
如果(!classInheritanceReferences.has(超类)){
种群遗传树([
超类.name,
{
值:超类
}
]);
}
//如果尚未包含该类,请将引用放入“classInheritanceReferences”中`
//含蓄地