children.length和childElementCount?

我們都知道,element.children返回子元素節點,那麼既然這樣,為什麼Element Traversal API還要添加諸如childElementCount,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 的反向遍歷)可以比通常的 for (let i = 0; i &< children.length; ++i) children[i] 獲得更好的性能。

最後,childElementCount 確實是多餘的介面。【小彩蛋:如果你打開 spec 的源碼會發現有一句注釋:&】

ElementTraversal API 是在2007年左右開始制定的,本源來自於 SVG Micro DOM 的需求(而不像其他 dom 新介面主要來自於瀏覽器廠商聯盟 WHATWG),原本是沒有 childElementCount 屬性的。當時從 SVG 工作組接手的 WebAPI 工作組加入了這個屬性,但並沒有將 children 屬性(原本是 IE 的私有介面)標準化列入議程。僅僅從 traversal 需求來說並不需要 children 屬性,但某些次要需求其實需要 children count(參見 ElementTraversal API 的代碼示例),所以就加了這個屬性。但 children 屬性標準化之後,這個 childElementCount 就變得多餘了。

其實在2011年左右,主導 HTML/DOM 標準制定的 WHATWG 有動議要刪除這個屬性,但是因為這個屬性在之前的3年中已經在所有主流瀏覽器里實現了(2008年到2010年間,Chrome 1+、FF 3.5+、Safari 4+、IE9+ 都實現了此屬性——是的,儘管很可能到今天還有許多前端並不知道這個介面的存在) ,所以到2012年年底的時候最後決定還是不刪除了。

最後,現在(2016年)的 dom 標準你應該直接看 W3C DOM4 ,ElementTraversal已經和DOM3一樣屬於上一代標準。或者你可以直接看上游的 WHATWG DOM Standard 。

以上。


為什麼Element Traversal API還要添加諸如childElementCount,firstElementChild,lastElementChild,previousElementSibling,nextElementSibling這些屬性?

為了使用者方便。

這些屬性是否多餘?

previousElementSibling,nextElementSibling不多餘,其他的確實冗餘。注意這裡是冗餘不是多餘,w3c明確說了部分API是出於易用性考慮而冗餘的,至於是否合理暫且不論。

1.1.4 Inheritance vs. Flattened Views of the API


The DOM Core APIs present two somewhat different sets of interfaces to an XML/HTML document: one presenting an
"object oriented" approach with a hierarchy of inheritance, and a "simplified" view that allows all manipulation to be
done via the Node interface without requiring casts (in Java and other C-like languages) or query interface calls in
COM environments. These operations are fairly expensive in Java and COM, and the DOM may be used in performance-critical environments, so we allow significant functionality using just the Node interface. Because many
other users will find the inheritance hierarchy easier to understand than the "everything is a Node" approach to the
DOM, we also support the full higher-level interfaces for those who prefer a more object-oriented API.


In practice, this means that there is a certain amount of redundancy in the API. The Working Group considers the
"inheritance" approach the primary view of the API, and the full set of functionality on Node to be "extra" functionality
that users may employ, but that does not eliminate the need for methods on other interfaces that an object-oriented
analysis would dictate. (Of course, when the O-O analysis yields an attribute or method that is identical to one on the
Node interface, we don"t specify a completely redundant one.) Thus, even though there is a generic Node.nodeName
attribute on the Node interface, there is still a Element.tagName attribute on the Element interface; these two attributes
must contain the same value, but the it is worthwhile to support both, given the different constituencies the DOM API
must satisfy.

—— w3c Document Object Model Core 1.1.4 https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1CED5498

以及這些屬性在實踐中和children相比,孰優孰劣?

沒有優劣,愛用哪個用哪個。


推薦閱讀:

如何理解js高程里的document對象是HTMLDocument的實例?

TAG:前端開發 | JavaScript | DOM |