1. 项目概述:从“两个对象”到前端世界的基石
刚接触前端开发时,听到DOM和BOM这两个词,很多人都会有点懵。它们听起来像是一对孪生兄弟,但又各司其职,是JavaScript与浏览器交互的核心桥梁。我最初也花了不少时间才理清它们的关系,后来在无数个项目里,从简单的页面交互到复杂的单页应用,深刻体会到对这两者理解得越透彻,写出的代码就越健壮、性能也越好。DOM和BOM不仅仅是API的集合,它们定义了JavaScript在浏览器这个“主场”中能做什么、能做到什么程度。今天,我们就抛开那些晦涩的定义,从实际应用和内部原理出发,彻底搞懂它们,让你在遇到“页面卡顿”、“兼容性报错”、“浏览器环境判断”这些问题时,能一眼看穿本质,快速找到解决方案。
简单来说, DOM(文档对象模型) 是你操作网页内容(HTML结构、样式、元素)的“手术刀”,而 BOM(浏览器对象模型) 则是你与浏览器窗口本身、以及浏览器所在环境(如屏幕、历史记录、地址栏)打交道的“遥控器”。一个对内,一个对外,共同构成了前端JavaScript能力的边界。理解它们的区别与联系,是进阶为资深前端开发者的必经之路。
2. DOM深度解析:不只是“找元素”和“改样式”
很多人对DOM的理解停留在 document.getElementById 和 element.style.color 这个层面,这就像只看到了冰山一角。DOM的本质是一个将HTML或XML文档抽象为树形结构的编程接口,这棵树上的每个节点都是一个对象,代表着文档的一部分。
2.1 DOM树的核心结构与节点类型
当你打开一个网页,浏览器解析HTML后,会构建一棵DOM树。这棵树不仅仅是元素(标签)的集合。
<!DOCTYPE html>
<html>
<head>
<title>示例</title>
</head>
<body>
<h1>你好,世界</h1>
<p>这是一个<strong>段落</strong>。</p>
<!-- 这是一个注释 -->
</body>
</html>
对于上面的HTML,DOM树会包含多种类型的节点:
- 文档节点(Document) :整个文档的根入口,即
document对象。 - 元素节点(Element) :如
<html>,<body>,<h1>,<p>,<strong>。这是我们最常打交道的类型。 - 文本节点(Text) :如“你好,世界”、“这是一个”、“段落”、“。”。元素标签内的纯文本内容。
- 属性节点(Attr) :在DOM规范中,元素的属性(如
id、class)也被视为节点,不过在现代API中,我们更多通过元素对象的属性(如element.id)来访问。 - 注释节点(Comment) :HTML中的注释内容。
理解节点类型至关重要。例如,当你用 firstChild 获取一个 <p> 标签的第一个子节点时,你得到的可能不是预期的 <strong> 元素,而是“这是一个”这个 文本节点 ,因为文本和元素是兄弟关系。这就是为什么有时我们会用 children (只包含元素节点)而非 childNodes (包含所有类型节点)来进行遍历。
注意 :在实际编码中,直接操作文本节点或注释节点的情况较少,但理解它们的存在能帮你避免一些意想不到的bug,尤其是在动态生成内容或进行精细化DOM操作时。
2.2 DOM操作:性能陷阱与最佳实践
DOM操作是昂贵的。每次修改DOM,都可能触发浏览器的 重排(Reflow) 和 重绘(Repaint) 。重排是计算元素几何信息(位置、尺寸)的过程,重绘是将像素绘制到屏幕的过程。重排必然导致重绘,反之则不然。
低效操作示例:
// 在循环中直接修改DOM,每次循环都会触发重排/重绘
const list = document.getElementById('myList');
for (let i = 0; i < 100; i++) {
const li = document.createElement('li');
li.textContent = `项目 ${i}`;
list.appendChild(li); // 糟糕!触发100次重排
}
高效操作实践:
- 使用文档片段(DocumentFragment) :它是一个轻量的“虚拟”DOM节点容器,在内存中操作,最后一次性插入真实DOM。
const list = document.getElementById('myList'); const fragment = document.createDocumentFragment(); for (let i = 0; i < 100; i++) { const li = document.createElement('li'); li.textContent = `项目 ${i}`; fragment.appendChild(li); } list.appendChild
553



被折叠的 条评论
为什么被折叠?



