跟随标准与Webkit源码探究DOM -- 获取元素之getElementById
按照ID获取元素 -- getElementById
标准
- DOM 1,定义在
HTMLDocumentInterface 中,原型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的更多相关文章
- 跟随标准与Webkit源码探究DOM -- 获取元素之querySelector,querySelectorAll
使用CSS选择器获取元素 -- querySelector,querySelectorAll(HTML5) 标准 W3C Selector API Level 1为Document,DocumentF ...
- 跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByClassName
按照类名获取元素 -- getElementsByClassName(HTML5) 标准 WHATWG 在Document与Element上均有定义,原型 HTMLCollection getElem ...
- 跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByTagName
按照标签名获取元素 -- getElementsByTagName 标准 DOM 1在Element和Document两个interface中均有定义,原型NodeList getElementsBy ...
- 跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByName
按照name属性获取多元素 -- getElementsByName 标准 DOM 1 定义在HTMLDocument Interface 中,原型NodeList getElementsByName ...
- ConcurrentHashMap源码探究 (JDK 1.8)
很早就知道在多线程环境中,HashMap不安全,应该使用ConcurrentHashMap等并发安全的容器代替,对于ConcurrentHashMap也有一定的了解,但是由于没有深入到源码层面,很多理 ...
- Vue源码探究-虚拟DOM的渲染
Vue源码探究-虚拟DOM的渲染 在虚拟节点的实现一篇中,除了知道了 VNode 类的实现之外,还简要地整理了一下DOM渲染的路径.在这一篇中,主要来分析一下两条路径的具体实现代码. 按照创建 Vue ...
- Vue源码探究-全局API
Vue源码探究-全局API 本篇代码位于vue/src/core/global-api/ Vue暴露了一些全局API来强化功能开发,API的使用示例官网上都有说明,无需多言.这里主要来看一下全局API ...
- Vue源码探究-事件系统
Vue源码探究-事件系统 本篇代码位于vue/src/core/instance/events.js 紧跟着生命周期之后的就是继续初始化事件相关的属性和方法.整个事件系统的代码相对其他模块来说非常简短 ...
- Vue源码探究-状态初始化
Vue源码探究-状态初始化 Vue源码探究-源码文件组织 Vue源码探究-虚拟DOM的渲染 本篇代码位于vue/src/core/instance/state.js 继续随着核心类的初始化展开探索其他 ...
随机推荐
- jenkins2 Jenkinsfile
推荐使用Jenkinsfile代替将groovy脚本直接写在jenkins job里. 文章来自:http://www.ciandcd.com文中的代码来自可以从github下载: https://g ...
- 挑灯熬夜看《Build 2015 Keynote》图文笔记
又是一年微软Build大会时间,网络上流传各种微软新品发布的消息终于也要揭晓了,一直熬夜到凌晨3点,好久没有这么兴奋了. 微软给力的很嘛! Satya nadella开始讲解 首先回顾微软的传统和技术 ...
- Unexpected namespace prefix "xmlns" found for tag Linear Layout
原文地址http://blog.csdn.net/taxuexumei/article/details/41523419 今天遇到的问题,,,保存到博客里,下回遇到找博客就行了,,,,,, 今天在制作 ...
- 【系统移植】kernel分析
内核启动流程 第二阶段 starte_kernel: | rest_init: | kernel_init | do_basic_setup(); // 加载驱动 | do_i ...
- paip.cache 缓存架构以及性能提升总结
paip.cache 缓存架构以及性能提升总结 1 缓存架构以及性能(贯穿读出式(LookThrough) 旁路读出式(LookAside) 写穿式(WriteThrough) 回写式 ...
- 微信小程序笔记(二)
微信小程序环境搭建与开发工具介绍 2-1 开篇介绍及下载工具 1.开发工具下载地址: http://t.cn/RVKH0HS 2.下载安装对应版本:win32,win64,mac; 2-2 小程序 ...
- Fiddler 修改返回内容 OnBeforeResponse 无效 没用
Fiddler自定义脚本可以实现很强大的内容替换,包括很有意义的——修改返回内容. 具体的方法可以参考官网:http://docs.telerik.com/fiddler/KnowledgeBase/ ...
- JavaScript 语句 while
while 语句用法 与for语句的用法之间的关系 for(i==1;i<5;i++) {document.write("12378<br />") } 若使用 ...
- EMW 性能优化二之---并发配置
EMW 性能优化二之---并发配置 在前一个日志中写到交货的异步更新,对于RFUI RF的前台操作会提升效率,异步更新不用等待更新状态的返回,启用更新队列的方式执行(SM13). 下面再补全性能相关的 ...
- 【转】IT 圈里有哪些经常被读错的词?
以下内容转至知乎,原文:http://www.zhihu.com/question/19739907?__nids__=5363833,5358751,5355121,5365018,5363846, ...