编者按:本文作者:贺师俊(网名 Hax),360 高级前端架构师,十多年来一直活跃在前端和 JavaScript 社区。对多项 Web 标准有微小贡献,对 Groovy 语言并间接对 Swift 语言有微小贡献,近年来参与了诸多 ECMAScript 新草案的讨论。曾设计和实现 Jedi 语言并用于生产环境,对自研编程语言略有一点实践经验。三次担任 QCon 出品人并获得「优秀出品人」荣誉,也经常在其他众多技术活动中担任讲师、嘉宾和主持人。
如何得到一个元素的子元素数量?
有基本 DOM API 常识的前端程序员可能第一时间想到 element.childNodes.length 。不过 childNodes 既包含元素节点也包含文本节点,所以你还需要遍历过滤,不太符合要求。
如果我们仔细查看DOM spec,会发现两个符合要求的 API:
element.children.length
element.childElementCount
那么问题来了,为什么同一件事情需要两个API呢?
children 返回所有子元素,看上去是比较有用的,那 childElementCount 是不是多余的呢?而且如果仔细看文档,跟 childElementCount 一起的 Element Traversal API (https://www.w3.org/TR/ElementTraversal/)还有一堆其他接口,包括 firstElementChild 、 lastElementChild 、 previousElementSibling 、nextElementSibling 。这些接口是否多余的呢?在实践中和 children 相比,孰优孰劣?
这是一个好问题。
我们分几点来说。
首先我们可以发现 previousElementSibling, nextElementSibling 并不是多余的,因为 children 接口做不到同样的事情。
其次 firstElementChild, lastElementChild 虽然等价于 children[0] 和 children[children.length - 1] ,但是前者避免了先生成一个 children 对象,所以是更直接且性能更好的接口(尤其是对 lastElementChild 来说)。
注意 children 是一个 live collection,按照通常的 DOM 实现来说,使用 firstElementChild 配合 nextElementSibling 的正向遍历(或者 lastElementChild 配合 previousElementSibling 的反向遍历)可以比基于children索引的遍历获得更好的性能。
for (let i = 0; i < e.children.length; ++i) {
process(e.children[i])
}
// better
for (let child = e.firstElementChild; child != null; child = child.nextElementSibling) {
process(child)
}
最后,childElementCount 确实是多余的接口。【小彩蛋:如果你打开 spec 的源码会发现有一句注释:<!-- childElementCount is redundant -->】
Element Traversal API 是在2007年左右开始制定的,本源来自于 SVG Micro DOM 的需求(而不像其他 DOM 新接口主要来自于浏览器厂商联盟 WHATWG),原本是没有 childElementCount 属性的。当时从 SVG 工作组接手的 WebAPI 工作组加入了这个属性,但并没有将 children 属性(比较老的前端应该知道这原本是 IE 的私有接口)标准化列入议程。仅仅从 traversal 需求来说并不需要 children 属性,但某些次要需求其实需要 children count(参见ElementTraversal API 的代码示例(https://www.w3.org/TR/ElementTraversal/#example-3.2)),所以就加了这个属性。但 children 属性标准化之后,这个 childElementCount 就变得多余了。
其实在2011年左右,主导 HTML/DOM 标准制定的 WHATWG 有动议要删除这个属性,但是因为这个属性在之前的3年中已经在所有主流浏览器里实现了(2008年到2010年间,Chrome 1+、FF 3.5+、Safari 4+、IE9+ 都实现了此属性——是的,尽管很可能到今天还有许多前端并不知道这个接口的存在) ,所以到2012年年底的时候最后决定还是不删除了。
最后,现在的 DOM 标准应该直接看 WHATWG DOM Standard (https://dom.spec.whatwg.org/) ,Element Traversal已经属于上一代标准了。
关于奇舞周刊
《奇舞周刊》是360公司专业前端团队「奇舞团」运营的前端技术社区。关注公众号后,直接发送链接到后台即可给我们投稿。