跟随标准与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 继续随着核心类的初始化展开探索其他 ...
随机推荐
- JS结构
当前页面的JS结构如下: <script> /* 这是立即执行的方法 */ (function () { /* 这是初始化表格 */ var init = fun ...
- 理解Javascript的异步等待
目前async / await特性并没有被添加到ES2016标准中,但不代表这些特性将来不会被加入到Javascript中.在我写这篇文章时,它已经到达第三版草案,并且正迅速的发展中.这些特性已经被I ...
- LINQ-to-SQL那点事~LINQ-to-SQL中的数据缓存与应对
回到目录 这个文章写的有点滞后了,呵呵,因为总想把之前不确定的东西确定了之后,再写这篇,之前的LINQ-to-SQL那点事,请点这里. LINQ-to-SQL中的数据缓存与应对 Linq-to-SQL ...
- 记录js的一些小技巧
1.取数组最大值,最小值 Math.max.apply(null,[1,2,3,32,3]); Math.min.apply(null,[1,2,3,32,3]); 2.旧版IE setTimeout ...
- atitit.基于http json api 接口设计 最佳实践 总结o7
atitit.基于http json api 接口设计 最佳实践 总结o7 1. 需求:::服务器and android 端接口通讯 2 2. 接口开发的要点 2 2.1. 普通参数 meth,p ...
- Command模式
Command模式只是封装了一个没有任何变量的函数. interface Command{ void Excute();} 具有强烈的分解功能的味道.把函数层面的任务提升到了类的层面(一个类仅仅是为了 ...
- SVN命令模式批量更新多个项目文件
使用svn作为版本管理是,在一个仓库下边同时建立多个项目,每天上班都需要一个个更新,为了发挥程序员懒的精神,能让电脑做的,绝不手工操作.作为自动化处理,在windows环境,首先想到了bat Tort ...
- 关于C# byte[]与struct的转换
转自:http://blog.chinaunix.net/uid-215617-id-2213082.html Some of the C# code I've been writing recent ...
- 开机SystemServer到ActivityManagerService启动过程分析
开机SystemServer到ActivityManagerService启动过程 一 从Systemserver到AMS zygote-> systemserver:java入层口: /** ...
- Win7下VS2010使用“ASP.Net 3.5 Claims-aware Template”创建ClaimsAwareWebSite报"HRESULT: 0x80041FEB"错误的解决办法
问题描述: 使用VS2010的WIF开发模板创建“Claims-aware ASP.NET Site”.“Claims-aware WCF Service”,下载安装后,创建网站时,报错"H ...