Skip to content

HTMLCollection 对象

HTMLCollection 的概念

HTMLCollection 是一个类数组对象,用于表示 HTML 文档中元素的集合。它是由 DOM 方法(如 getElementsByClassName()getElementsByTagName() 等)返回的,包含了匹配指定选择器的所有元素。

HTMLCollection 的特性

  1. 实时性:HTMLCollection 是实时的(live),意味着当文档发生变化时,它会自动更新以反映这些变化
  2. 类数组:HTMLCollection 是类数组对象,具有 length 属性,可以通过索引访问元素,但不具有数组的方法(如 forEachmap 等)
  3. 有序性:HTMLCollection 中的元素按照它们在文档中的顺序排列

HTMLCollection 的方法和属性

length

length 属性返回 HTMLCollection 中元素的数量:

javascript
const paragraphs = document.getElementsByTagName('p');
console.log(paragraphs.length); // 输出: 段落数量

item()

item() 方法返回 HTMLCollection 中指定索引的元素:

javascript
const paragraphs = document.getElementsByTagName('p');
const firstParagraph = paragraphs.item(0);
console.log(firstParagraph); // 输出: 第一个 <p> 元素

// 与直接使用索引访问相同
const firstParagraph2 = paragraphs[0];
console.log(firstParagraph2); // 输出: 第一个 <p> 元素

namedItem()

namedItem() 方法返回 HTMLCollection 中具有指定 ID 或 name 属性的元素:

javascript
const elements = document.getElementsByClassName('item');
const elementWithId = elements.namedItem('myItem');
console.log(elementWithId); // 输出: 具有 ID "myItem" 的元素

// 与直接使用命名访问相同
const elementWithId2 = elements['myItem'];
console.log(elementWithId2); // 输出: 具有 ID "myItem" 的元素

HTMLCollection 的遍历

1. for 循环

使用传统的 for 循环遍历 HTMLCollection:

javascript
const paragraphs = document.getElementsByTagName('p');

for (let i = 0; i < paragraphs.length; i++) {
  console.log(paragraphs[i].textContent);
}

2. for...of 循环

使用 for...of 循环遍历 HTMLCollection:

javascript
const paragraphs = document.getElementsByTagName('p');

for (const paragraph of paragraphs) {
  console.log(paragraph.textContent);
}

3. 转换为数组后遍历

将 HTMLCollection 转换为数组后,使用数组方法遍历:

javascript
const paragraphs = document.getElementsByTagName('p');

// 使用 Array.from() 转换
const paragraphsArray = Array.from(paragraphs);
paragraphsArray.forEach(paragraph => {
  console.log(paragraph.textContent);
});

// 使用扩展运算符转换
const paragraphsArray2 = [...paragraphs];
paragraphsArray2.forEach(paragraph => {
  console.log(paragraph.textContent);
});

// 使用数组方法
const paragraphsArray3 = Array.prototype.slice.call(paragraphs);
paragraphsArray3.forEach(paragraph => {
  console.log(paragraph.textContent);
});

HTMLCollection 与 NodeList 的区别

特性HTMLCollectionNodeList
实时性实时(live)大多数方法返回的是静态的(static),但 childNodes 返回的是实时的
元素类型只包含元素节点包含各种类型的节点(元素、文本、注释等)
方法item(), namedItem()item(), entries(), forEach(), keys(), values()
遍历可以使用 for 循环和 for...of 循环可以使用 for 循环、for...of 循环和 forEach 方法

HTMLCollection 的应用场景

1. 动态元素操作

由于 HTMLCollection 是实时的,它适合用于需要动态响应文档变化的场景:

javascript
const list = document.getElementById('list');
const items = list.getElementsByTagName('li');

console.log(items.length); // 输出: 当前 li 元素数量

// 添加新元素
const newItem = document.createElement('li');
newItem.textContent = '新项';
list.appendChild(newItem);

console.log(items.length); // 输出: 数量自动增加

2. 批量元素操作

HTMLCollection 可以用于批量操作元素:

javascript
// 为所有段落添加类
const paragraphs = document.getElementsByTagName('p');
for (let i = 0; i < paragraphs.length; i++) {
  paragraphs[i].classList.add('highlight');
}

// 为所有输入元素添加事件监听器
const inputs = document.getElementsByTagName('input');
for (let i = 0; i < inputs.length; i++) {
  inputs[i].addEventListener('focus', function() {
    this.classList.add('focused');
  });
  
  inputs[i].addEventListener('blur', function() {
    this.classList.remove('focused');
  });
}

HTMLCollection 的最佳实践

1. 缓存长度

在遍历 HTMLCollection 时,缓存 length 属性可以提高性能:

javascript
// 好的做法:缓存长度
const paragraphs = document.getElementsByTagName('p');
for (let i = 0, len = paragraphs.length; i < len; i++) {
  console.log(paragraphs[i].textContent);
}

// 不好的做法:每次循环都访问 length
const paragraphs = document.getElementsByTagName('p');
for (let i = 0; i < paragraphs.length; i++) {
  console.log(paragraphs[i].textContent);
}

2. 转换为数组

如果需要使用数组方法,可以将 HTMLCollection 转换为数组:

javascript
// 好的做法:转换为数组后使用数组方法
const paragraphs = document.getElementsByTagName('p');
const paragraphsArray = Array.from(paragraphs);

// 使用 forEach
paragraphsArray.forEach(paragraph => {
  console.log(paragraph.textContent);
});

// 使用 map
const texts = paragraphsArray.map(paragraph => paragraph.textContent);
console.log(texts);

// 使用 filter
const longParagraphs = paragraphsArray.filter(paragraph => paragraph.textContent.length > 100);
console.log(longParagraphs);

3. 注意实时性

由于 HTMLCollection 是实时的,修改文档可能会影响遍历:

javascript
// 注意:在遍历过程中修改文档可能会导致意外结果
const list = document.getElementById('list');
const items = list.getElementsByTagName('li');

// 错误:在遍历过程中删除元素会导致索引变化
for (let i = 0; i < items.length; i++) {
  list.removeChild(items[i]); // 会跳过元素
}

// 正确:从后向前遍历
for (let i = items.length - 1; i >= 0; i--) {
  list.removeChild(items[i]);
}

// 或者:转换为数组后遍历
const itemsArray = Array.from(items);
itemsArray.forEach(item => {
  list.removeChild(item);
});

4. 选择合适的 DOM 方法

根据具体需求选择合适的 DOM 方法:

  • 需要实时更新:使用 getElementsByClassName()getElementsByTagName()(返回 HTMLCollection)
  • 不需要实时更新:使用 querySelectorAll()(返回 NodeList,静态)
  • 只需要一个元素:使用 getElementById()querySelector()

HTMLCollection 的常见错误

1. 尝试使用数组方法

HTMLCollection 不是数组,不能直接使用数组方法:

javascript
const paragraphs = document.getElementsByTagName('p');

// 错误:HTMLCollection 没有 forEach 方法
// paragraphs.forEach(paragraph => {
//   console.log(paragraph.textContent);
// });

// 正确:转换为数组后使用
Array.from(paragraphs).forEach(paragraph => {
  console.log(paragraph.textContent);
});

2. 遍历过程中修改文档

在遍历 HTMLCollection 时修改文档可能会导致意外结果:

javascript
const list = document.getElementById('list');
const items = list.getElementsByTagName('li');

// 错误:在遍历过程中删除元素会导致索引变化
for (let i = 0; i < items.length; i++) {
  console.log(items[i].textContent);
  list.removeChild(items[i]); // 会跳过元素
}

// 正确:从后向前遍历
for (let i = items.length - 1; i >= 0; i--) {
  console.log(items[i].textContent);
  list.removeChild(items[i]);
}

// 或者:转换为数组后遍历
const itemsArray = Array.from(items);
itemsArray.forEach(item => {
  console.log(item.textContent);
  list.removeChild(item);
});

3. 混淆 HTMLCollection 和 NodeList

HTMLCollection 和 NodeList 是不同的对象,具有不同的特性:

javascript
// HTMLCollection(实时)
const paragraphs1 = document.getElementsByTagName('p');

// NodeList(静态)
const paragraphs2 = document.querySelectorAll('p');

// 添加新元素
const newP = document.createElement('p');
newP.textContent = '新段落';
document.body.appendChild(newP);

console.log(paragraphs1.length); // 输出: 数量增加
console.log(paragraphs2.length); // 输出: 数量不变

小结

HTMLCollection 是一个实时的类数组对象,用于表示 HTML 文档中元素的集合。它具有实时性、类数组和有序性等特性,可以通过索引访问元素,也可以使用 item()namedItem() 方法。在使用 HTMLCollection 时,应该注意其实时性可能带来的影响,合理选择遍历方法,并在需要时将其转换为数组以使用数组方法。