原文發佈在個人獨立博客上 ~: 從DOM選擇器的返回值提及javascript
拋開大大解放生產力的jQuery,使用JS獲取元素要使用getElementById方法,或相似的getElementsByTagName, getElementsByClassName,getElementsByName. 第一種狀況下,根據ID獲取時,返回值是惟一的元素;而根據TagName, ClassName 等獲取時候,返回值是包含全部符合條件的多個元素的「列表」。此處「列表」要加雙引號,是由於嚴格來講,JavaScript乃至DOM元素中並無所謂「列表」或List的數據類型/對象,既然不能稱爲列表,那麼它們究竟是啥?html
這篇blog就試圖從getElement(s)的返回值提及,往上扯一些早就該瞭解,但老是似懂非懂的簡單的DOM基礎知識。前端
getElementsByClassName('myClass')
獲取指定類名爲myClass的元素,getElementsByTagName('some-tag')
獲取標籤爲'some-tag'的元素,它們的返回值都是 HTMLCollection
對象
java
getElementsByName('myName')
獲取標記了name屬性爲myName的元素,它的返回值是NodeList
對象
node
getElementById('myId')
獲取惟一id屬性爲myId的元素。有趣的是,當訪問該元素的constructor.name屬性時,能夠獲得不一樣的值。form元素對應HTMLFormElement對象, main標籤則對應HTMLElement對象,這應該是從面向對象的角度看,不一樣類型的元素屬於不一樣的對象實例。
ajax
querySelector
和querySelectorAll
方法是HTML5新增的Web API,它們接受selector參數,selector正是咱們經常使用的CSS選擇器。不一樣之處在於,querySelector('form')返回的是頁面中的第一個'form'元素,而querySelectorAll('form')返回NodeList
類型,它們是全部form的列表。
編程
接着來看這兩個對象,它們都由多個元素組成一個「列表」,或者說「數組」,咱們也能夠像使用數組同樣方便地用下標訪問單個元素。可是它們僅僅是Array-like,並無Array對象的其餘經常使用方法,好比forEach.segmentfault
javascriptvar buttons = document.getElementsByTagName('button'); console.log(buttons[1]); // 輸出第2個button元素 console.log(buttons.forEach); // undefied console.log(buttons.filter); //undefied var next_nodes = document.getElementsByName('next'); console.log(next_nodes[0]); //輸出列表中第1個元素 console.log(next_nodes.forEach); //undefied
除了以上提到的getElements方法以外數組
在使用getElements方法時,NodeList和HTMLCollection好像並沒什麼不一同樣的,可是從字面上講,一個是節點列表,一個是HTML(元素)集合,並非一回事。他們的不一樣能夠從另外兩個方法看出,它們是childNodes和children,下面是一個合適的例子。瀏覽器
html<div><!-- this is a comment --> text in div <a>Link</a> <strong> Strong Text <a>Strong Link</a> </strong> </div>
javascriptmydiv = document.querySelector('div'); console.log(mydiv.children); // 不含#text "text in div"和註釋 console.log(mydiv.childNodes); // 含文字"text in div"和註釋
<div>
的子標籤表明的元素,因此示例中的text in span並不屬於span.children因此它們不一樣就在於一個獲取的是元素,一個獲取全部節點。
到底元素和節點有什麼不一樣,看原型鏈。
以<a>
元素爲例,調用mydiv.children[0].constructor.name
,可知<a>Link</a>
元素的類型HTMLAnchorElement
; HTMLAnchorElement的原型鏈爲:
HTMLAnchorElement --> HTMLElement --> Element --> Node --> EventTarget --> Object
調用mydiv.childNodes[0].constructor.name
,可知<!-- this is a comment -->
節點的對象類型Comment
,相似也能夠獲得文本節點的類型Text
,它們的原型鏈爲:
Comment --> CharacterData --> Node --> EventTarget --> Object
Text --> CharacterData -- Node -- EventTarget --> Object
看到原型鏈就能夠豁然開朗了,Node是包含Element和Text, Comment在內的概念,而HTMLElement只是Node的一個子集。
除了上面示例的幾個節點類型,Node包含的類型以下;對任意一個節點myNode,myNode.nodeType屬性就是它的類型。
圖片截自 MDN, thumb down圖標表明廢棄API,是不推薦使用的類型
終於扯到最基本的DOM概念了,DOM事關重大,然而原理其實也就是兩句話的事兒。
DOM == Document Object Modle(文檔結構模型),瀏覽器收到一個HTML頁面後,根據頁面結構構建一個DOM樹,DOM樹就是由不一樣類型的節點(Node)所組成的。在HTML文檔中,一條註釋語句是一個Node,一個HTML元素也是Node,甚至<!DOCTYPE html>
也是一個Node。有了Node對象,一輩子二,二生三,三生萬物;除了事件和ajax請求,前端編程說白了就剩下來使用瀏覽器提供的DOM API來對Node進行各類操做。
固然,觀察Node的原型鏈,能夠看處處於它上一層的是 EventTarget
對象,這意味着Node都繼承了EventTarget
的屬性和方法,最多見的固然是.addEventListener
。這正是javascript在前端可以實現各類可能性的緣由,一切節點均可以綁定事件。
參考:
1. DOM概述 | MDN
2. Node - Web API Interfaces | MDN
3. NodeList - Web API Interfaces | MDN
4. HTML5中類jQuery選擇器querySelector的使用 - SegmentFault