Gahing's blog Gahing's blog
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Gahing / francecil

To be best
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 前端基础

    • 编程语言

      • CSS

      • HTML

        • LearningHTML
        • htmlparser实现
        • inline-block 文本宽度溢出问题
        • svg笔记
        • css与js的阻塞关系
        • document-write重写
        • getElementsByClassName遍历时出现的问题
          • 前言
          • 以下写法都是ok的
          • 补充
          • 参考
        • 前端小知识-格式化标签
        • 前端监听资源加载错误
        • 浅谈 View Transitions API
        • 通读 HTML Standard
      • JavaScript

      • Rust

      • TypeScript

      • WebAssembly

    • 开发工具

    • 前端调试

    • 浏览器原理

    • 浏览器生态

  • 应用框架

  • 工程能力

  • 应用基础

  • 专业领域

  • 业务场景

  • 大前端
  • 前端基础
  • 编程语言
  • HTML
gahing
2018-07-15
目录

getElementsByClassName遍历时出现的问题

# 前言

我们需要遍历 .lyad 的元素,并将其 className 中的 lyad 删掉。

最开始的做法是

var s = 'lyad'
var eles = document.querySelectorAll('.'+'s');
for (var j = 0,len=eles.length; j < len; j++) {
  eles[j].className = eles[j].className.replace(s, '')
}
1
2
3
4
5

没有任何问题。

查询文档以及自测,发现 getElementsByClassName 的速度比 querySelectorAll 快很多,5倍以上。

为了性能考虑,我们改为以下写法:

var eles = document.getElementsByClassName(s)
for (var j = 0,len=eles.length; j < len; j++) {
  eles[j].className = eles[j].className.replace(s, '')
}
1
2
3
4

不出意外,会报 Cannot read property 'className' of undefined 错误。

观察发现,一开始 eles 为四个,在访问 eles[2] 的时候出错,说明此时 eles.length===2 ,访问了一个空元素。

即, getElementsByClassName 得到的元素其对应 className 被删掉的话,eles 会自动删去其元素。

做个测试:

var eles = document.getElementsByClassName('lyad')
console.log(eles.length) //4
eles[0].className = eles[0].className.replace('lyad', '')
console.log(eles.length) //3
1
2
3
4

# 以下写法都是ok的

var eles = document.getElementsByClassName('lyad')
while(eles.length>0){
  eles[0].className = eles[0].className.replace('lyad', '')
}
1
2
3
4

注意 eles 获取要用 getElementsByClassName 而不是 querySelectorAll 否则将导致死循环。

var eles = document.getElementsByClassName('lyad')
for (var j = 0,len=eles.length; j < len; j++) {
  eles[0].className = eles[0].className.replace('lyad', '')
}
1
2
3
4

注意 len 需要用临时变量保存,否则每次获取将会得到不同的 length 导致提前结束。

相比上一种写法更安全。

# 补充

上面写法有差异,在于NodeList对象的不同表现。

大多数情况下,NodeList 对象都是个实时集合。

意思是说,如果文档中的节点树发生变化,则已经存在的 NodeList 对象也可能会变化。

在另一些情况下,NodeList 是一个静态集合,也就意味着随后对文档对象模型的任何改动都不会影响集合的内容。document.querySelectorAll 返回一个静态的 NodeList。

引用自:https://developer.mozilla.org/zh-CN/docs/Web/API/NodeList

同时,这也解释了为何getElementsByClassName获取NodeList的速度比querySelectorAll快。

因为前者仅返回 列表的引用地址 仅访问时才实时获取数据 , 而后者一开始就要获取和封装所有数据。

DynamicNodeList 对象通过在cache缓存中 注册它的存在 并创建。 从本质上讲, 创建一个新的 DynamicNodeList 是非常轻量级的, 因为不需要做任何前期工作。 每次访问 DynamicNodeList 时, 必须查询 document 的变化, length 属性 以及 item() 方法证明了这一点(使用中括号的方式访问也是一样的).

相比之下, StaticNodeList 对象实例由另一个文件创建,然后循环填充所有的数据 。 在 document 中执行静态查询的前期成本上比起 DynamicNodeList 要显著提高很多倍。

# 参考

DOM中的动态NodeList与静态NodeList

编辑 (opens new window)
#HTML
上次更新: 2024/09/01, 23:56:56
document-write重写
前端小知识-格式化标签

← document-write重写 前端小知识-格式化标签→

最近更新
01
浅谈代码质量与量化指标
08-27
02
快速理解 JS 装饰器
08-26
03
Vue 项目中的 data-v-xxx 是怎么生成的
09-19
更多文章>
Theme by Vdoing | Copyright © 2016-2024 Gahing | 闽ICP备19024221号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式