從JS遍歷DOM樹學演算法
從簡單的需求/面試題談起
自定義一個方法去檢查DOM中某個ID的元素。類似getElementById.
先推薦閱讀下:
ofollow,noindex">廣度優先 .
// HTML結構如下 <div class="wrapper"> <section class="header"> <div class="logo"></div> </section> <section class="main"> <div class="sidebar"> <ul class="menu"> <li class='li'> <a href="" id='demo'>li1-a</a> </li> <li class='li'> <a href="">li2</a> </li> </ul> </div> </section> <section class="footer"> <div class="copyright"></div> </section> </div> 複製程式碼
簡單畫了下DOM節點(只考慮元素節點)圖:

程式碼實現
- 深度優先, 遞迴實現
const cusGetElementByIdByDFS = function (parentNode, id) { // 深度優先, 遞迴實現 if (parentNode) { let target = null; const children = Array.from(parentNode.children); if (parentNode.id === id) { return parentNode; } for (let i = 0; i < children.length; i++) { target = cusGetElementByIdByDFS(children[i], id); if (target) { return target; } } } return null; } 複製程式碼
// 測試程式碼 console.log(cusGetElementByIdByDFS(document.querySelector('.wrapper') , 'demo')) 複製程式碼
- 深度優先, 非遞迴實現, 使用棧
const cusGetElementByIdByDFS2 = function (parentNode, id) { if (!parentNode) { return null; } // 深度優先, 非遞迴實現, 使用棧 let stack = []; if (parentNode.id === id) { return parentNode; } for (let i = parentNode.children.length; i > 0; i--) { stack.push(parentNode.children[i - 1]); } while (stack.length) { let node = stack.pop(); if (node.id === id) { return node; } else { if (node.children.length > 0) { stack = Array.from(node.children).concat(stack); } } } } 複製程式碼
// 測試程式碼 console.log(cusGetElementByIdByDFS2(document.querySelector('.wrapper') , 'demo')) 複製程式碼
- 廣度優先 非遞迴實現
const cusGetElementByIdByBFS = function (parentNode, id) { // 廣度優先 非遞迴實現 // 佇列的思想: 採用出隊的方式遍歷節點,如果遍歷到的節點有子節點,則將子節點入隊 const layer = []; // 按照順序存放每個層級的每個節點 if (parentNode) { // 初始化layer // 節點深度從父節點開始算起 layer.push({ node: parentNode, depth: 1 }); while (layer.length > 0) { const root = layer.shift(); // 出隊 if (root.node.id === id) { return root; // 包括對應節點和節點深度 } else { if (root.node.children.length > 0) { Array.from(root.node.children).forEach(node => { layer.push({ node, depth: root.depth + 1 }) }) } } } } return null; } 複製程式碼
// 測試程式碼 console.log(cusGetElementByIdByBFS(document.querySelector('.wrapper') , 'demo')) 複製程式碼

後續看細下演算法書再做補充, 初次學習有勘誤請指出。