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