现代 JavaScript 教程实战:用 DOM 遍历统计嵌套列表的后代数量(tree-info 任务解析) 文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载本篇技术指南基于 zh.javascript.info 仓库中《节点属性typetag 和 content》章节的实战练习任务「计数后代」2-tree-info/task.md以一棵嵌套的ul/li树为场景完整讲解如何遍历 DOM 节点、读取文本节点内容、统计元素后代数量并深入剖析querySelectorAll、firstChild.data、getElementsByTagName等核心 API 的底层机制与适用边界。读完本文你将能够独立完成为每个树节点显示标题与子孙数量这类典型的 DOM 操作需求并理解 DOM 节点类层次EventTarget → Node → Element → HTMLElement对属性与方法的决定性影响。任务背景一棵真实的嵌套列表树任务给出了一个典型的树状导航结构完整 HTML 见 source.view/index.htmlul liAnimals ul liMammals ul liCows/li liDonkeys/li liDogs/li liTigers/li /ul /li liOther ul liSnakes/li liBirds/li liLizards/li /ul /li /ul /li liFishes ul liAquarium ul liGuppy/li liAngelfish/li /ul /li liSea ul liSea trout/li /ul /li /ul /li /ul任务要求对每一个li元素分别输出两件事它自身的文本内容不含子树中的文本例如Animals而不是Animals Mammals Cows ...它嵌套的后代li数量这里的后代指所有层级的深层后代而非仅直接子级。例如根级别的Animals项应显示Animals: 2它下面直接挂Mammals与Other两个 li而Mammals应显示Mammals: 4Cows、Donkeys、Dogs、Tigers。三步解法从选择节点到读取文本再到统计后代官方参考解法完整可运行版本见 solution.view/index.html由三个相互衔接的步骤构成。第一步用querySelectorAll选中全部lifor (let li of document.querySelectorAll(li)) { // ... }querySelectorAll由Element类提供返回的是符合 CSS 选择器的全部匹配元素组成的集合NodeList天然支持for...of迭代。它执行的是一次全文档范围的元素级搜索——这正是Element类提供元素级导航与搜索方法getElementsByTagName、querySelector这一能力的具体体现见 article.md 中对 DOM 节点类的说明。由于querySelectorAll的匹配范围是所有后代所以无论树嵌套多深每一个li都会被选中且只被选中一次这正好满足为每个li显示的需求。第二步用firstChild.data读取标题文本每个li的内部结构是这样的先是文本节点如Animals然后是子元素节点嵌套的ul。因此标题文本恰是li的第一个子节点——一个Text类型的节点for (let li of document.querySelectorAll(li)) { let title li.firstChild.data; // title 是 li 中任何其他节点之前的文本 }这里用到了两个关键知识点firstChild由Node类提供的属性返回节点的第一个子节点不区分节点类型可能是元素、文本或注释。data即nodeValueCharacterData抽象类的属性用于读写文本节点、注释节点等非元素节点的内容。innerHTML只对元素节点有效而文本节点对应的是nodeValue和data两个几乎等价的属性官方文档明确建议使用data因为它更短。官方解法在读取后还做了收尾处理title title.trim();去除文本节点两侧可能存在的换行与空格原始 HTML 中li与文本之间可能存在格式化空白。第三步用getElementsByTagName(li)统计后代let count li.getElementsByTagName(li).length; alert(title : count);getElementsByTagName同样是Element类提供的方法与querySelectorAll的关键差异在于它只在当前元素的后代范围内搜索因此li.getElementsByTagName(li)返回的正是当前li内部所有层级的嵌套lilength即为后代总数。这正是任务所要求的所有后代包括深层嵌套的后代——getElementsByTagName的搜索天然是递归的无需自己编写递归函数。将三步组合就是完整解法for (let li of document.querySelectorAll(li)) { // 从第一个子节点文本节点读取标题 let title li.firstChild.data; title title.trim(); // 去掉首尾多余空白 // 统计该 li 内部嵌套的所有后代 li let count li.getElementsByTagName(li).length; alert(title : count); }运行后依次弹出Animals: 2、Mammals: 4、Other: 3、Cows: 0、Donkeys: 0、Dogs: 0、Tigers: 0、Fishes: 2、Aquarium: 2、Guppy: 0、Angelfish: 0、Sea: 1、Sea trout: 0。为什么会踩坑三个必须理解的 DOM 细节这个任务之所以被评为 importance 5 的高价值练习是因为它精准地检验了三个容易出错的概念。细节一li的第一个子节点是文本节点而不是ul如果把li.firstChild误认为是嵌套的ul就会读不到标题。firstChild不区分节点类型对于liAnimalsul...这样的结构子节点顺序是文本节点Animals→ 元素节点ul。要跳过文本直接拿元素应使用firstElementChildElement类提供只返回元素节点而要拿文本内容则正好用firstChild.data。细节二nodeType是判断节点类型的硬核手段article.md明确指出nodeType是查看节点类型的传统数值属性1表示元素节点3表示文本节点9表示 document 对象且只读。在本任务中可以这样验证li的第一个子节点确实是文本节点alert(li.firstChild.nodeType); // 3 文本节点细节三getElementsByTagName返回活集合live collection与querySelectorAll返回静态快照不同getElementsByTagName返回的是动态更新的HTMLCollection。在本任务中二者结果一致但当你后续动态增删 DOM 节点时HTMLCollection会实时反映变化而NodeList不会。选择哪个 API 取决于你是否需要活引用。从任务到实战这些 DOM 属性的完整图谱本任务是 article.md 中节点属性type、tag 和 content知识点的集中演练场。该章总结的全部核心属性在此任务中都能找到用武之地属性任务中的角色性质nodeType验证子节点类型元素1文本3document9数值、只读nodeName/tagName获取标签名HTML 模式下恒为大写如LI只读tagName仅元素可用innerHTML元素内 HTML 内容可读写可修改插入的script不会执行outerHTML元素完整 HTML写入不会改元素本身而是替换 DOM 位置可修改但有陷阱nodeValue/data本任务读取标题文本的核心firstChild.data文本/注释节点内容可读写textContent元素内纯文本去标签写入时特殊字符按字面处理可安全插入用户文本可读写hidden等价于styledisplay:none的简洁开关可读写其中与本任务最相关的两组对应关系值得强调元素节点读innerHTML非元素节点读datainnerHTML只对元素有效文本节点和注释节点必须通过nodeValue/data读写。任务中title li.firstChild.data正是这种分工的典型用法。读文本用data写文本用textContent若任务改为把用户输入的标题写入li正确做法是li.textContent userInput——它把所有符号按字面处理不会把b之类的输入变成真实标签是防 XSS 的安全写入方式。同章节其他任务巩固同样的概念本练习所在的 05-basic-dom-node-properties 目录下还有两个姊妹练习用更刁钻的角度巩固相同的知识nodeType 中是什么问script执行时document.body.lastChild.nodeType是多少。陷阱在于脚本执行瞬间浏览器尚未解析完页面其余部分lastChild就是正在执行的script元素本身答案是1元素节点——这提醒我们DOM 是随着解析逐步构建的。注释中的标签body.innerHTML !-- body.tagName --之后body.firstChild.data是什么答案是BODY——因为tagName在 HTML 模式下恒为大写且data读取注释节点内容!--...--内部文本的能力同样适用于注释节点不只是文本节点。这两个任务与「计数后代」共同验证了同一批核心结论tagName大写规则、firstChild与data的节点类型无关性、脚本执行时机的 DOM 状态。把它们放在一起练习能一次性打通节点类型 内容读取 遍历搜索三条主线。总结「计数后代」这个练习虽然代码只有几行却是 DOM 基础能力的试金石querySelectorAll负责全文档选择、firstChild负责定位文本子节点、data负责读取非元素节点内容、getElementsByTagName负责在子树内递归计数后代。理解每个 API 的类归属Node提供树导航Element提供元素搜索和类型差异元素 vs 文本 vs 注释才是写出健壮 DOM 代码的前提。建议直接打开 solution.view/index.html 在浏览器中运行观察每一步弹窗结果再结合 article.md 的完整属性表做变体实验例如把标题改为textContent写入、把计数改为querySelectorAll(:scope ...)就能彻底掌握树形 DOM 的遍历与统计技巧。赞分享文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载相关推荐现代 JavaScript 教程实战用 DOM 遍历为嵌套 ul/li 树计数后代节点现代 JavaScript 教程实战用 DOM 遍历为嵌套 ul/li 树计数后代节点 导读 本篇基于《现代 JavaScript 教程》The Moder文档教程前端现代 JavaScript 教程遍历嵌套 ul/li 树统计每个节点的后代数量现代 JavaScript 教程遍历嵌套 ul/li 树统计每个节点的后代数量 导读 本文围绕《Modern JavaScript Tutorial》仓库中文档/教程前端JavaScript 实战统计树形列表中每个节点的后代数量DOM 遍历与文本节点 data 修改JavaScript 实战统计树形列表中每个节点的后代数量DOM 遍历与文本节点 data 修改 导读 本篇以《Modern JavaScript Tut文档/教程前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考