當我們選取「多個」元素時(例如用 querySelectorAll 或 getElementsByTagName),JavaScript 回傳給我們的並不是真正的「標準陣列(Array)」,而是一個「類陣列(Array-like object)」。
這些類陣列主要分為 NodeList 與 HTMLCollection 兩種。
究竟它們有什麼差別?為什麼有時候可以用 .forEach(),有時候又會出錯?
就像是拍一張貓咪的拍立得,在按下相機(執行 querySelectorAll)的那一刻,照片就定格了。
即使後來網頁上動態新增或刪除了元素(有新的貓走過來或原本的貓移動到別的地方),NodeList 裡面的內容與數量都不會改變。
就像「貓咪的實況攝影」:它是即時連線的。
如果透過 JavaScript 在網頁中動態加入新的 HTML 標籤(例如新的貓走過來),HTMLCollection 會立刻自動更新數量與內容。
forEach?)| 特性 / 方法 | NodeList | HTMLCollection |
|---|---|---|
| 回傳該物件的語法 | document.querySelectorAll() |
getElementsByClassName()、getElementsByTagName() |
| 包含的節點類型 | 可以包含任何 DOM 節點(元素、文字、註解等) | 只包含 HTML 元素節點(Element Nodes) |
| 即時性(Live) | 通常為靜態 (Static)(註 1) | 動態 (Live) |
可以用 .forEach() 嗎? |
可以(現代瀏覽器內建支援) | 不行(會報錯 TypeError) |
可以用 length 與 [i] 索引嗎? |
可以 | 可以 |
(註 1:少數例外如 element.childNodes 回傳的 NodeList 是動態的,但最常用的 querySelectorAll 回傳者為靜態。)
優先使用 querySelectorAll:回傳的 NodeList 不僅寫法統一(CSS 選擇器),還支援 .forEach() 處理,不容易因為 DOM 動態變化而產生預期之外的連動 Bug。
需要動態追蹤時才用傳統語法:只有當明確需要「集合隨時跟著網頁元素增刪而自動更新」時,才使用 HTMLCollection 系列。
遇到不能 .forEach 的時候:記得用 Array.from() 轉陣列!
個人筆記:
JavaScript 基礎概念 | 什麼是 DOM ?如果網頁是一隻貓
JS DOM | 取得元素的方法:querySelector、querySelectorAll 與傳統選擇器