按照类名获取元素 -- getElementsByClassName(HTML5)

标准

  • WHATWG 在DocumentElement上均有定义,原型 HTMLCollection getElementsByClassName(DOMString classNames),并定义了匹配算法类名的提取算法,注意这里是先从参数里提取出类名作为一个set,然后再开始匹配的。其中指明了在quirks mode下类名大小写不敏感,否则大小写敏感
  • DOM 4(DocumentElement )基本和WHATWG一致

注意点

按照标准里的说法,“Unless otherwise stated, a collection must be live. ”。既然标准没有指明getElementsByClassName的返回值说是static的,那么它返回的HTMLCollection就是live的。

WHATWG描述getElementsByClassName的实现是先从参数里用ASCII空白字符分割出类名,将得到的类名组成一个有序集合之后,将能够匹配集合内所有类名的元素返回。除非在quirks mode否则大小写敏感,DocumentElement上均有定义。

兼容性

  • 属于HTML5新出现的API,IE9+ 及其他浏览器的现行版本均支持

WebKit代码分析

和之前的几个方法一样,在ContainerNode里实现,使用ClassNodeList作为NodeListsNodeData::addCacheWithAtomicName<>的template specialization。之前的一次commitnodeMatches改为了elementMatches,不过github上的mirror里似乎ClassNodeList还没改掉。ClassNodeListnodeMatches过滤标准(参考WebCore/dom/ClassNodeList.h)为:

if (!element->hasClass())
return false;
if (!m_classNames.size())
return false;
// FIXME: DOM4 allows getElementsByClassName to return non StyledElement.
// https://bugs.webkit.org/show_bug.cgi?id=94718
if (!element->isStyledElement())
return false;
return element->classNames().containsAll(m_classNames);

可以看到里面目前有个多余的StyledElement判定……这里首先判断要过滤的元素有没有class或者传入的字符串是否不含有效的class,接着检查元素是否为StyledElement(找不到相关文档,不过Node.h里的enum ConstructionType可以看出哪些元素是StyledElement)。

类名的提取实现在SpaceSplitStringClassNodeListElementData有SpaceSplitStringm_classNames来维护类名集合。这些外部的类通过调用SpaceSplitString::set来更新和设置类名,而SpaceSplitString::set又调用SpaceSplitStringData::create来维护存有集合的私有成员SpaceSplitStringData m_data

SpaceSplitStringData::create有两个重载,外部调用的是SpaceSplitStringData::create (const AtomicString& keyString)。里面首先调用维护缓存的spaceSplitStringTable(实质是一个static的hashmap)来检查是否已经有缓存,如果没有则开始创建集合。 WebCore/dom/SpaceSplitString.cpp里的tokenizeSpaceSplitString实现了将类名字符串tokenize的算法,并且每分解出一个token,就会调用参数tokenProcessorprocessTokenSpaceSplitStringData::create (const AtomicString& keyString)首先以TokenCounter作为tokenProcessor调用tokenizeSpaceSplitString,将类名字符串先扫描一次统计token数目以方便分配内存,接着调用重载的SpaceSplitStringData::create(const AtomicString& keyString, unsigned tokenCount),里面使用TokenAtomicStringInitializer作为tokenProcessor再扫描一次字符串,将每个token的内容保存到分配好的内存里。

判断匹配的算法就比较粗暴了……参见WebCore/dom/SpaceSplitString.cpp的containsAll和WebCore/dom/SpaceSplitString.h的contains会发现,居然是线性查找套线性查找的O(mn)(m和n分别为要查找的类名数和被查找的元素的实际类名数)……不过考虑到应用场景下一般类名很少,多点也就五六个了,被查找的类名可能更少,乘起来mn可能最多也就二三十左右,一般大概不会超过十,此时用高级数据结构带来的overhead可能还大过简单的线性查找,所以这样实现也是合理的。

跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByClassName的更多相关文章

  1. 跟随标准与Webkit源码探究DOM -- 获取元素之querySelector,querySelectorAll

    使用CSS选择器获取元素 -- querySelector,querySelectorAll(HTML5) 标准 W3C Selector API Level 1为Document,DocumentF ...

  2. 跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByTagName

    按照标签名获取元素 -- getElementsByTagName 标准 DOM 1在Element和Document两个interface中均有定义,原型NodeList getElementsBy ...

  3. 跟随标准与Webkit源码探究DOM -- 获取元素之getElementById

    按照ID获取元素 -- getElementById 标准 DOM 1,定义在HTMLDocument Interface 中,原型Element getElementById(in DOMStrin ...

  4. 跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByName

    按照name属性获取多元素 -- getElementsByName 标准 DOM 1 定义在HTMLDocument Interface 中,原型NodeList getElementsByName ...

  5. ConcurrentHashMap源码探究 (JDK 1.8)

    很早就知道在多线程环境中,HashMap不安全,应该使用ConcurrentHashMap等并发安全的容器代替,对于ConcurrentHashMap也有一定的了解,但是由于没有深入到源码层面,很多理 ...

  6. Vue源码探究-虚拟DOM的渲染

    Vue源码探究-虚拟DOM的渲染 在虚拟节点的实现一篇中,除了知道了 VNode 类的实现之外,还简要地整理了一下DOM渲染的路径.在这一篇中,主要来分析一下两条路径的具体实现代码. 按照创建 Vue ...

  7. Vue源码探究-全局API

    Vue源码探究-全局API 本篇代码位于vue/src/core/global-api/ Vue暴露了一些全局API来强化功能开发,API的使用示例官网上都有说明,无需多言.这里主要来看一下全局API ...

  8. Vue源码探究-事件系统

    Vue源码探究-事件系统 本篇代码位于vue/src/core/instance/events.js 紧跟着生命周期之后的就是继续初始化事件相关的属性和方法.整个事件系统的代码相对其他模块来说非常简短 ...

  9. Vue源码探究-状态初始化

    Vue源码探究-状态初始化 Vue源码探究-源码文件组织 Vue源码探究-虚拟DOM的渲染 本篇代码位于vue/src/core/instance/state.js 继续随着核心类的初始化展开探索其他 ...

随机推荐

  1. ios 项目里常用的宏

    NSLog(@"__func__ :  %s", __func__);//oc测试环境,打印文件名,方法名 NSLog(@"__FUNCTION__ : %s" ...

  2. Origin的图片导出问题

    很多会议投稿都会要求提交的pdf文件用的是type1字体,因为type1字体是矢量字体,无论怎么放大缩小都不会失真.一旦pdf里嵌入了其他非矢量字体,例如type3字体,就会通不过测试,一个典型的例子 ...

  3. AT&T Assembly for Linux and Mac (sys_exit)

    Exit() in C : (sys_exit.c) int main(void) { ; } Exit() in AT&T for Linux: (sys_exit.s) .section ...

  4. super和this区别

    * super()和this()类似,区别是,super()从子类中调用父类的构造方法,this()在同一类内调用其它方法. 4.super和this的异同: 1)super(参数):调用基类中的某一 ...

  5. 阿里云产品介绍(二):云服务器ECS的孪生兄弟们

    上一篇介绍的云服务器ECS,是阿里云最基础的产品,也是每一个云计算厂商最基础的产品,俗称爆款.除了标准的云服务器,阿里云也不停的在推出面向特殊业务场地的云服务器,可以说是ECS的孪生兄弟们. 这一篇就 ...

  6. OpenCV相机标定和姿态更新

    原帖地址: http://blog.csdn.net/aptx704610875/article/details/48914043 http://blog.csdn.net/aptx704610875 ...

  7. C语言:stat,fstat和lstat函数

    这三个函数的功能是一致的,都用于获取文件相关信息,但应用于不同的文件对象.对于函数中给出pathname参数,stat函数返回与此命名文件有关的信息结构,fstat函数获取已在描述符fields上打开 ...

  8. python ide: pycharm

    1, 设置python路径 2,运行py文件 https://www.jetbrains.com/help/pycharm/2016.1/creating-and-running-your-first ...

  9. 奇怪吸引子---Thomas

    奇怪吸引子是混沌学的重要组成理论,用于演化过程的终极状态,具有如下特征:终极性.稳定性.吸引性.吸引子是一个数学概念,描写运动的收敛类型.它是指这样的一个集合,当时间趋于无穷大时,在任何一个有界集上出 ...

  10. Redis监控技巧(转)

    来自:http://blog.nosqlfan.com/html/4166.html Redis 监控最直接的方法当然就是使用系统提供的 info 命令来做了,你只需要执行下面一条命令,就能获得 Re ...