1

正在读取其中一个这些MDN页面,我在下面看到了类似SVG的东西,其中对象接口指向它继承的另一个接口:

<svg style=“display:inline-block;position:absolute;top:0;left:0;”viewBox=“-50 0 600 120”preserveSpectRatio=“xMinYMin-met”><a xlink:href=“https://developer.mozilla.org/en-US/docs/Web/API/EventTarget网站“target=”_top“><rect x=”1“y=”1”width=“110”height=“50”fill=“#fff”stroke=“#D4DDE4”stroke-width=“2px”></rect><text x=“56”y=“30”font-size=“12px”font-family=“Consolas,Monace,Andale Mono,monospace”fill=“#4D4E53”text-anchor=“middle”alignment-baseline=“midle”>EventTarget</text></a><points=“111,25 121,20 121,30 111,25“冲程=”#D4DDE4“fill=”none“></pollyline><line x1=”121“y1=”25“x2=”151“y2=”25”stroke=“#D4DDA4”></line><a xlink:href=“https://developer.mozilla.org/en-US/docs/Web/API/Node网站“target=”_top“><rect x=”151“y=”1“width=”75“height=”50“fill=”#fff“stroke=”#D4DDE4“stroke-width=”2px“></rect><text x=”188.5“y=“30”font-size=“12px”font-family=“Consolas,Monaco,Andale Mono,monospace”fill=“#4D4E53”text-anchor=“middle”alignment-baseline=“midth”>节点</text></a><points=“226,25 236,20 236,30 226,25“冲程=”#D4DDE4“fill=”none“></pollyline><line x1=”236“y1=”25“x2=”266“y2=”25”stroke=“#D4DDE2”></line><a xlink:href=“https://developer.mozilla.org/en-US/docs/Web/API/Element网站“target=”_top“><rect x=”266“y=”1“width=”75“height=”50“fill=”#fff“stroke=”#D4DDE4“stroke-width=”2px“></rect><text x=”303.5“y=“30”font-size=“12px”font-family=“Consolas,Monaco,Andale Mono,monospace”fill=“#4D4E53”text-anchor=“middle”alignment-baseline=“midth”>元素</text></a><points=“341,2 5 351,20 351,30 341,25“冲程=”#D4DDE4“fill=”none“></pollyline><line x1=”351“y1=”25“x2=”381“y2=”25”stroke=“#D4DDA4”></line><a xlink:href=“https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement网站“target=”_top“><rect x=”381“y=”1“width=”110“height=”50“fill=”#fff“stroke=”#D4DDE4“stroke-width=”2px“></rect><text x=”436“y=“30”font-size=“12px”font-family=“Consolas,Monaco,Andale Mono,monospace”fill=“#4D4E53”text-anchor=“middle”alignment-baseline=“midth”>HTMLElement</text></a><points=”491,25 501,20 501,30 491,25“冲程=”#D4DDE4“fill=”none“></pollyline><line x1=”501“y1=”25“x2=”509“y2=”25”stroke=“#D4DDA4”></line><line x1=“509”y1=“25”x2=“508”y2=“90”stroke=“#D4DDE2”>https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement“target=”_top“><rect x=”291“y=”65“width=”200“height=”50“fill=”#F4F7F8“stroke=”#D4DDE4“stroke-width=”2px“></rect>HTMLTableCellElement(HTML表格单元格元素)svg>

总的来说,我注意到他们都继承了事件目标,然后节点等等。

我想知道:所有这些关系都有一个完整的可视化吗?可能以树状表示。

12
  • 非常不清楚。。。一方面,您询问web API,甚至链接到这些API的列表,然后只显示DOM对象接口的列表。你对哪一个感兴趣?我的意思是,你意识到第一个名单中没有成员在第二个名单中,对吧?
    – 凯伊多
    评论 2021年5月17日22:56
  • 1
    我是这方面的初学者,我不清楚他们的区别。我最终进入了该列表中的SVG,所以我认为他们是一样的。我对DOM对象接口很感兴趣。我会尝试更新这个问题。 评论 2021年5月18日6:46
  • 你的问题和你发布的内容之间肯定有脱节。继承是一种JavaScript构造。是的,DOM是JavaScript对页面的表示,但DOM节点之间的连接方式与继承无关。关于树可视化:HTML层次结构实际上是一棵树。DOM(HTML的直接表示)也是一棵树,这绝非巧合。
    – 安得烈
    评论 2021年5月18日6:54
  • @安德鲁再次提到MDN文章,上面写着:它通过其父元素继承属性那么,这与JavaScript继承有什么不同呢? 评论 2021年5月18日7:09
  • @逻辑攀登者那篇文章说“通过它的父元素”在哪里?我在文章中没有看到。但我确实认为HTML表格单元格元素继承自HTML元素。描述的继承是JavaScript对象继承。
    – 安得烈
    评论 2021年5月18日8:33

1答案1

重置为默认值

工具

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

获取原型

JavaScript中的继承通过对象的内部原型工作。可以通过以下方式进行观察对象.get原型.这个原型派生构造器(函数)的属性是基本构造器的实例(函数);及其原型属性是原型链的下一步。

这些关系阐明了这一点:

Object.getPrototypeOf(Node.prototype)===EventTarget.protoype//节点从EventTarget原型继承属性(EventTarget是节点的超类)。Object.getPrototypeOf(EventTarget.prototype)===Object.protoype//EventTarget从对象原型继承属性(Object是EventTarget的超类)。Object.getPrototypeOf(Object.prototype)===null//对象不从任何东西继承属性(Object是基类)。

请注意,构造函数的继承行为可能会产生误导,并且不是我们要使用的:

Object.getPrototypeOf(Node)===EventTarget//这行得通,不是吗?Object.getPrototypeOf(EventTarget)===Function.prototype//函数不是EventTarget的超类;这只是构造函数的基础,构造函数是一个函数。Object.getPrototypeOf(Object)====Function.prototype//这里只显示Function,因为构造函数是它的实例。

当尝试读取对象报告的内部原型时,原型链结束无效的,在Web浏览器中,最初只发生在Object.getPrototypeOf(Object.prototype).这适用于所有内置和主机定义的构造函数,除了代理,它没有原型属性,尽管它是构造函数。它不需要这样做的原因是代理“实例”(即。新代理(目标,处理程序))使用构造时获取第一个参数(代理目标)的原型新的.我们暂时不讨论这个问题。

获取所有类

由于大多数内置和主机定义的构造函数都是全局的,因此可以获取所有构造函数,但以下情况除外类型数组.使用Object.getOwn属性描述符生成所有全局属性及其描述符。(在网上,窗口可以代替全球This,在Node上,它是全球的.)

描述符包含一些设置,例如,如果可以在对于在里面环路等。如果属性是getter/setter对,您将看到相应的得到设置功能。任何正常属性都具有价值描述符。没有构造函数是getter/setter对,因此价值必须存在,并且由于施工人员是全球性的财产,我们正在寻找功能.如前所述,这些构造函数必须具有原型属性,或是代理.

Object.entries(Object.getOwnPropertyDescriptors(globalThis)).filter(([_,{value}])=>value===Proxy||typeof value===“function”&&value.hasOwnProperty(“prototype”)

这将获得所有构造函数的列表,但由于代理是一种特殊情况,并且对象有一个讨厌的“Null Prototype”要处理,让我们实际过滤掉它们并手动处理它们。

const allConstructors=Object.entries(Object.getOwnPropertyDescriptors(globalThis)).filter(([_,{value}])=>值!==Object&&typeof value===“function”&&value.hasOwnProperty(“prototype”);

生成树

我们将初始化三个地图秒:

  • 类继承树是具有继承结构的树。
  • 类继承引用是一个平面结构,将每个构造函数映射到中的引用类继承树.
  • 构造函数名称将每个构造函数映射到与其关联的任何名称。
const classInheritanceTree=新映射([[无效的,新建地图([[对象,新建地图()]])],]),classInheritanceReferences=新映射([[null,classInheritanceTree.get(null)],[对象,classInheritanceTree.get(null).get(对象)]]),constructorNames=新映射([[无效的,新建集合([“空”])],[对象,新建集合([“对象”])]]);

当然,无效的不是真正地继承树的一部分,但出于可视化目的,它充当有用的树根。请注意.构造函数.名称不总是与上的属性名称匹配全球This,例如在Firefox 90中:webkitURL.name===“URL”网络套件CSSMatrix.name===“DOMMatrix”、以及webkitURL===URLWebKitCSSMatrix===DOMMatrix.这就是为什么构造函数名称设置包含所有别名的。

我们通过迭代所有构造函数并确定建造师他们的原型。的自我调用populateInheritanceTree函数只确保超类存在于地图s,然后将其子类放入结构中。类继承树仅隐式填充为类继承引用填充:后者包含对地图在前一个中,所以通过更新一个,我们也改变了另一个。

allConstructors.forEach(函数populateInheritanceTree([name,{value}]){const superClass=Object.getPrototypeOf(value.prototype).constructor;//确保超类包含在`classInheritanceReferences`;中;//使用与超类对应的参数调用函数本身。if(!classInheritanceReferences.has(superClass)){填充命名树([超级类名称,{值:superClass}]);}//如果尚未包含该类,请在“classInheritanceReferences”中放置引用`//并隐式放入`classInheritanceTree`(通过`.get(superClass)`)。//这两个Map值引用相同的Map引用:`subClasses`。if(!classInheritanceReferences.has(value)){const subClasses=新映射();类继承引用.set(值,子类).get(超类).set(值,子类);}//为所有名称和别名创建集合。if(!constructorNames.has(value)){constructorNames.set(value,new set());}//添加属性名称。constructorNames.get(值).add(名称);//如果构造函数的“name”属性存在(可能不同),请添加该属性。if(value.name){constructorNames.get(值).add(value.name);}});

可视化树

一旦我们有了类继承树,让我们把它们放入<ul><li>结构。我们将添加一个数据崩溃属性来跟踪哪些元素是可展开的,哪些元素是展开的,而哪些元素是折叠的。

const visualizeTree=(map,names)=>Array.from(map).map(([构造函数,subMap])=>{const listItem=document.createElement(“li”),listItemLabel=document.createElement(“span”);listItemLabel.append(…Array.from(names.get(constructor)).flatMap((textContent)=>[Object.assign(document.createElement(“代码”){text内容}),", "]).切片(0,-1);listItem.append(listItemLabel);if(subMap.size){const-subList=document.createElement(“ul”);listItem.setAttribute(“data-collapsed”,“false”);listItem.append(subList);subList.append(…可视化树(subMap,名称));}return listItem;});document.body.appendChild(document.createElement(“ul”)).append(…visualizeTree(classInheritanceTree,constructorNames));

我们按字母顺序对列表项目进行排序,但首先列出可扩展的项目。剩下的只是一些UI处理和CSS…

所有构造函数的树(除了代理)在Web上公开(正常的浏览器上下文,而不是Worker)

此代码将前面的所有步骤放在一起。单击每个可展开的项目以展开或折叠它。底部还有一张结果图片。

然而,我知道您已经询问过有关Web API或DOM API的问题。这些很难自动隔离,但希望现在已经有所帮助。

读者练习:自动包含树中每个名称的MDN链接。

“使用严格”;const allConstructors=Object.entries(Object.getOwnPropertyDescriptors(globalThis)).filter(([_,{value}])=>值!==Object&&typeof value===“function”&&value.hasOwnProperty(“prototype”)),classInheritanceTree=新映射([[无效的,新建地图([[对象,新建地图()]])]]),classInheritanceReferences=新映射([[null,classInheritanceTree.get(null)],[对象,classInheritanceTree.get(null).get(Object)]]),constructorNames=新映射([[无效的,新建集合([“空”])],[对象,新建集合([“对象”])]]),visualizeTree=(map,names)=>Array.from(map).map(([构造函数,subMap])=>{const listItem=document.createElement(“li”),listItemLabel=document.createElement(“span”);listItemLabel.append(…Array.from(names.get(constructor)).flatMap((textContent)=>[Object.assign(document.createElement(“代码”){text内容}),", "]).切片(0,-1);listItem.append(listItemLabel);if(subMap.size){const-subList=document.createElement(“ul”);listItem.setAttribute(“data-collapsed”,“false”);listItem.append(subList);subList.append(…可视化树(subMap,名称));}return listItem;}).sort((listItemA,listItemB)=>listItemB.hasAttribute(“data-collapsed”)-listItemA.hasAttribute;allConstructors.forEach(函数populateInheritanceTree([名称,{值}]){const superClass=Object.getPrototypeOf(value.prototype).constructor;if(!classInheritanceReferences.has(superClass)){populateInheritanceTree([超级类名称,{值:superClass}]);}if(!classInheritanceReferences.has(value)){const-subClasses=新映射();类继承引用.set(值,子类).get(超类).set(值,子类);}if(!constructorNames.has(value)){constructorNames.set(value,new set());}constructorNames.get(值).add(名称);if(value.name){constructorNames.get(值).add(value.name);}});document.body.appendChild(document.createElement(“ul”)).append(…visualizeTree(classInheritanceTree,constructorNames));addEventListener(“点击”,({target})=>{if(target.closest(“span”)&&target.losest((“li”).hasAttribute(“data-collapsed”)){target.closest(“li”).setAttribute(“data-collapsed”,JSON.stringify(!JSON.parse(target.crosest(”li“).getAttribute(”data-collabsed“)));}});
ul公司{向左填充:2em;}李{向左填充:.3em;列表样式类型:光盘;}li[data-collapsed]>span{光标:指针;}li[data-collapsed]>span:悬停{背景:#ccc;}li[data-collapsed='false']{列表样式类型:“▼”;}li[data-collapsed='true']{列表样式类型:'▶';}li[data-collapsed='true']>ul{显示:无;}

这是我的Firefox Nightly 90.0a1.

4
  • “Web上可用的所有构造函数”。。。这些只是在Window上下文中公开的。其他上下文可以访问其他API(例如WorkerLocation、PaintRenderingContext2D等)
    – 凯伊多
    评论 2021年5月20日4:23
  • @凯伊多说得好。我已经修改了小节标题。因此,这是读者的另一个练习:可视化Worker和Node.js中公开的所有构造函数的树。😉 评论 2021年5月20日14:59
  • 非常感谢您的回答!您可以将其保存在github存储库中吗?这样,如果有人想添加您提到的链接,或者对Node执行相同的操作,他们可以将所有内容放在同一位置。 评论 2021年8月6日16:59
  • 1
    @逻辑爬山者嗯,我会考虑的。在此期间,您可以用此代码自己创建一个GitHub回购。 评论 2021年8月6日21:09

你的答案

单击“发布您的答案”,表示您同意我们的服务条款并确认您已阅读我们的隐私政策.

不是你想要的答案吗?浏览已标记的其他问题问你自己的问题.