按照ID获取元素 -- getElementById

标准

  • DOM 1,定义在HTMLDocument Interface 中,原型Element getElementById(in DOMString elementId),当不存在拥有对应ID的元素时返回null,该方法不会抛出任何异常。
  • DOM 2,移动到了Document(原HTMLDocument的Parent Interface),原型不变。
  • DOM 3 特别声明浏览器应当使用Attr.isId判断 Attr 是否为 ID,同时加了一句“Attributes with the name "ID" or "id" are not of type ID unless so defined.”,这是针对IE7-会将name为"id"的元素也一并返回的错误实现增加的说明
  • WHATWG 将getElementById 放到了 NonElementParentNode里,因此实现了NonElementParentNode的DocumentFragment也拥有这个方法(而W3C的标准里,DocumentFragment仅仅继承了Node,不应该有此方法)
  • DOM 4 目前与 WHATWG 相同

注意点

  • 注意 getElementById 的名字里没有全大写的 ID,而是id。
  • 目前浏览器中 getElementById 仅定义在Document 和 DocumentFragment上,WHATWG的文档里提到没有添加到Element是为这个特性会挂掉未使用sizzle前的jQuery(<=1.2.6)的单元测试(旧版jQuery使用了elem.getElementById来判断元素是否为Document),参见邮件列表上的讨论。
  • 没有插入 DOM (如用appendChild)的元素是无法用该方法搜索到的。由于前面提到的WHATWG与W3C标准的不同,现实中浏览器里的DocumentFragment也可以用此方法搜索元素。
  • 一些浏览器会将带有id的元素创建成全局变量(比如id="foo"的元素会以window.foo出现在javascript runtime),并且为了向后兼容所以一直保留这个特性,但是它不在标准里,而且全局变量很容易被覆盖,应该尽量避免使用。
  • 标准里写明了当存在多个拥有对应 id 的元素时,浏览器的行为是未定义的,但是大多数浏览器都选择返回第一个拥有该 id 的元素。至于什么是“第一个”,就要看浏览器实现中的DOM树是怎么遍历的了。 WHATWG 里描述的是tree-order,即先序的DFS。

    检查方法:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Document</title>
    </head>
    <body>
    <div>
    <div id="foo" class="a"></div>
    </div>
    <div id="foo" class="b"></div>
    </body>
    </html>

    浏览器 console 运行

    document.getElementById('foo')

    Chrome,FireFox及IE均返回class="a"的div,即 WHATWG 中规定的先序DFS。

兼容性

IE7- 会将有与查询id相同的name的元素也算入,因此如果需要兼容 IE7-,可能需要做elem.id === id的判定。

其他

DOM 2 中,id 定义在 HTMLElement上(DOM 3 没有 DOM HTML 标准),WHATWG 将 id 放在了 Element,定义都是attribute DOMString id,并说明了 id 属于global attribute。总之,在 HTML 里只要是元素就可以有id,并且可以通过 elem.id 的方式直接获取。

Webkit 相关代码分析

Document 继承自 TreeScope,即WHATWG里提到的NonElementParentNode (参见WebCore/dom/Document.h),getElementById其实实现在TreeScope里,调用私有变量DocumentOrderedMap指针m_elementsById 的getElementById(WebCore/dom/TreeScope.h, WebCore/dom/TreeScope.cpp)。

DocumentOrderedMap的getElementById其实是get的包装,最终实现参见 WebCore/dom/DocumentOrderedMap.cpp

迭代器的继承结构是 descendantsOfType -> TypedElementDescendantIteratorAdapter -> TypedElementDescendantIterator,TypedElementDescendantIterator<ElementType>::operator++ 调用 ElementIterator<ElementType>::traverseNext ,参见TypedElementDescendantIterator.h。

ElementIterator<ElementType>::traverseNext 再调用 Traversal<ElementType>::next(WebCore/dom/ElementIterator.h),这里多态的ElementTraversal(继承Traversal)实际上又调用了NodeTraversal,NodeTraversal中 next的重载利用traverseNextTemplate实现。最后通过WebCore/dom/NodeTraversal.h可以看出访问顺序是 firstChild -> nextSibling -> nextAncestorSibling,也就是先序DFS,符合WHATWG里的描述。

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

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

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

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

    按照类名获取元素 -- getElementsByClassName(HTML5) 标准 WHATWG 在Document与Element上均有定义,原型 HTMLCollection getElem ...

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

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

  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. Node.js 爬虫,自动化抓取文章标题和正文

    持续进行中... 目标: 动态User-Agent模拟浏览器 √ 支持Proxy设置,避免被服务器端拒绝 √ 支持多核模式,发挥多核CPU性能 √ 支持核内并发模式 √ 自动解码非英文站点,避免乱码出 ...

  2. JavaScript 火的有点过头了,但又能火多久呢?

    2016年的前端是遍地开花的一年,各种前端框架,各种库,学都学不完,反正在前端的世界里,没有什么是JavaScript实现不了的... JavaScript 你还能再火几年?? 前些年node被捧上天 ...

  3. PHP动态压缩js,css

    PHP动态压缩js,css 列表项 标签: PHP 正式发布产品时,我们希望将项目里的js,css合并压缩,以减少http请求.防止轻易查看源代码. 使用 只需要在头部引入一下代码即可: <me ...

  4. paip.中文 分词 -- 同义词大全整理

    paip.中文 分词 -- 同义词大全整理 同义词的处理方法: 作者Attilax  艾龙,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http://blo ...

  5. 测量行业(RTK)相关的小知识总结

    RTK测量系统,一般需要先架设基准站(参考站),数据链模式外挂大电台(有天线大功率模式,理想范围方圆18公里以内).基准站通过收到卫星(多星)进行计算出当前的位置. 其中涉及到频率的设置,波特率,以及 ...

  6. This in JavaScript

    声明 本文仅为读书笔记并致力于理解Js中的this关键字.如有雷同,纯属巧合.原因有二,其一:有幸看了同一本书,其二:this这玩意已被说烂了~ 为什么要用this? this提供了优雅的方式隐式传递 ...

  7. 诚聘Android开发工程师

    职位要求1.有1年以上Android应用项目经验或相关经验: 2.熟悉Android操作系统和Android SDK,GUI编程及GDI的使用:熟练掌握Android 的 UI 系统控件及常用布局.动 ...

  8. MySQL Cluster 7.3.3 官方版本下载

    MySQL Cluster 是 MySQL 适合于分布式计算环境的高实用.高冗余版本.它采用了NDB Cluster 存储引擎,允许在1个 Cluster 中运行多个MySQL服务器.在MyQL 5. ...

  9. Lowest Common Ancestor of Two Nodes in a Binary Tree

    Reference: http://blog.csdn.net/v_july_v/article/details/18312089  http://leetcode.com/2011/07/lowes ...

  10. Page和UserControl的事件加载顺序

    UC OnInitPage OnInit Page Page_LoadPage OnLoad UC Page_LoadUC OnLoad Page OnPreRenderUC OnPreRender