我們先來看一張DOM Tree的圖
DOM 節點有分層的概念,節點與節點之間的關係我們大致上可以分成兩種:
父子關係:
除了 document
之外,每一個節點都會有個上層的節點,我們通常稱之為「父節點」 (Parent node),而相對地,從屬於自己下層的節點,就會稱為「子節點」(Child node)。
兄弟關係:有同一個「父節點」的節點,那麼他們彼此之間就是「兄弟節點」(Siblings node)。
有時候你無法直接用名稱或選擇器找到節點,這時候就必須透過關係。
簡單解釋一下這個流程,依然拿之前的案例來做說明:
這是一篇文章其中有一篇文章的標題是Professional Sports
,當今天我必須要回傳在這個標題裡所有放在<li>
的文字內容(別問我為什麼要回傳XD),這時候在DOM Tree的查找路徑會是:
從<h4>Professional Sports</h4>
出發。
找到他的兄弟<ul>
。
在找到<ul>
的children(孩子)<li>
。
而這個從樹狀結構裡查找資料的動作就是我們今天的主題**traverse**
。
我們來看一下語法:
parentElement
:返回元素的父級元素。nextElementSibling
:返回元素的下一個兄弟元素。previousElementSibling
:返回元素的前一個兄弟元素。firstElementChild
:返回元素的第一個子元素。lastElementChild
:返回元素的最後一個子元素。我們在之前那個案例來實際操作一下吧:
其中要特別說一下最一開始的HTMLCollection(5)
,還記得昨天我們有說到NodeList
嗎?
如果忘記也沒關係,我們在看一下:
NodeList
很類似於Array ,但它並不是真正的 Array。
它不能新增刪除元素,只有幾個簡單的唯讀操作:
length
forEach
像 HTMLCollection()
跟 NodeList
很類似於Array ,但它並不是真正的 Array的,我們有一個專有的名詞,叫做Array-like object
但一般我們都會叫他Array-like
。
詳細的內容這邊就不說了,有興趣的朋友再去網路上看。
大家如果在網路上看資料時,想必都會看到另外一組語法:
parentNode
、nextSibling
、previousSibling
、firstChild
和 lastChild
為什麼會有兩組呢?我們先來看一下實際操作後大家應該就會知道差別在哪裡了:
為什麼這組語法出來的結果會有這麼多的text啊?主要還是我們在排版程式碼時的「換行/縮排」,會產生隱藏的文字節點。詳細內容大家可以到 MDN 看,我這邊就是簡單提一下。
至於這兩種語法的區別,我個人的解讀是在於它們如何處理節點。其中 parentElement
和 nextElementSibling
等屬性和方法只會考慮元素節點(Element Node),而忽略其他類型的節點,如文字節點、註釋節點等。而 parentNode
和 nextSibling
等屬性和方法則會考慮所有類型的節點。
這是我自己的解讀,如果有錯還請大家指教!
我在知乎跟稀土上有看到兩篇文章,大家也可以參考一下:知乎參考文章、稀土參考文章
當我們想對一個陣列裡的每個元素都執行某個方法時,除了傳統的 for 迴圈外,還可以使用什麼呢?就讓我們一起看下去:
for
使用情境:
[0, 1, 2]
中的每一個數字for(let i = 0; i < 3; i++){
console.log(i);
}
// 0
// 1
// 2
arr.forEach
使用情境:
語法:
array.forEach(function(currentValue, index, arr), thisValue)
currentValue :當前陣列元素的值
index :當前陣列元素的 index
arr :當前陣列本身。
我們用一個範例來解釋:
const scores = [1, 2, 3]
let sum = 0
scores.forEach(function (score, index) {
console.log(`現在輸到第 ${index} 項,值是 ${score}`)
sum += score
console.log(`現在總和是: ${sum}`)
})
由於這個函式只會在 forEach
裡面運作,別的地方用不到,因此沒有特別取名的必要。因此可以使用箭頭函式:
const scores = [1, 2, 3]
let sum = 0
scores.forEach((score, index) => {
console.log(`現在輸到第 ${index} 項,值是 ${score}`)
sum += score
console.log(`現在總和是: ${sum}`)
})
其結果為:
有兩點要注意:
forEach
沒有回傳值:forEach
方法的角色是領路人,把陣列中的每個元素依序交給 function 處理,交付完它的任務就結束了。for…of
語法:
for (variable of iterable)
statement
variable
:在每次迭代中從序列中接收一個值。可以是使用 const、let 或 var 進行聲明,也可以是分配目標(例如之前聲明的變數、物件屬性或解構賦值模式)。iterable
:一個可迭代的 object。 作為迴圈運作的值序列的來源。statement
:在每次迭代中要執行的陳述式。一樣我們用一個範例來解釋:
const array1 = ['a', 'b', 'c'];
for (const element of array1) {
console.log(element);
}
// Expected output: "a"
// Expected output: "b"
// Expected output: "c"
至於跟他很像的for…in我很少用到比較沒有那麼清楚,這邊附上PJ大神所寫的文章讓大家參考。
map
語法:
const newArray = array.map((currentValue, index, array) => {
// return newValue based on currentValue
});
currentValue
: 目前迭代的陣列元素的值。index
(選填): 目前迭代的陣列元素的索引。array
(選填): 原始的陣列。map()
方法的主要特點是它不會改變原始陣列,而是返回一個新的陣列,其中每個元素都是經過回呼函式處理後的結果。
看個案例會更加清楚:
const array1 = [1, 4, 9, 16];
// Pass a function to map
const map1 = array1.map((x) => x * 2);
console.log(map1);
// Expected output: Array [2, 8, 18, 32]
終於寫完了,但有幾個遍歷的方法我並沒有寫出來,是因為這邊所列的都是我在這段學習過程中有使用到且還記得的><”
沒寫出來的應該是我沒用過、或是我真的忘了。
但很多資料也都只寫到這些,應該還行啦。