标签:des style blog http io ar color 使用 sp
getElementsByName
HTMLDocument
Interface 中,原型NodeList getElementsByName(in DOMString elementName)
,该方法不会抛出任何异常。HTMLDocument
,原型不变,但是新增说明在 HTML4.0 里搜索范围为所有元素,而 XHTML 1.0 里搜索范围缩小到表单元素Document
所属的 DOM core标准,但HTMLDocument
属于 DOM HTML 而不属于 DOM core)Document
而不是另开一个 `HTMLDocument,原型不变name
和 id
不同,可以重复,因此这个方法名字里有“s”,并且返回的是NodeList
NodeList
,当页面元素改变后,再次调用获得的NodeList
会跟着更新。null
,是一个空的NodeList
name
有两种,一种已经在该元素的IDL里,另一种只是名字为name
的属性(Attr
)document.name
这种直接获取name为name
的元素的方式,但这个特性并未出现在标准中,一些新的浏览器也开始不支持这种获取方式了,所以最好不要用IE9- 只算入 HTML4 允许带 name 的元素(换句话说,只算入IDL里有name
的元素)。但是它们又有一个 bug :算入任何 id 与所搜索的name相同的元素。
检查
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div id="foo"></div> <a name="bar"></a> <div name="baz"></div> </body> </html>
IE 9- 下:
document.getElementsByName(‘baz‘).length
返回 0(因为 HTML 4 中 div 不能带name)document.getElementsByName(‘foo‘).length
返回 1(算入了 HTML 4 中不能带 name 但 id 与查询的name相同的div)document.getElementsByName(‘bar‘).length
返回 1,是正常行为。FireFox 与 Chrome 返回 1,0,1,即允许任意元素带 name,且不会将 id 与 name混淆。
因此在IE 9-下,使用该方法获取的元素可能还需要用 elem.name == name
进行过滤。
此外,某些IE版本返回的不是NodeList
,HTMLCollection
,不过因为HTMLCollection
兼容NodeList
,所以没有大碍。
在 DOM HTML 里,name
只出现在一部分元素的IDL里(有哪些元素的IDL里带有attribute DOMString name 可参见 DOM Level 2 和 WHATWG,或者参考HTML4 DTD),而其他元素的name
实际上是作为一个普通的Attr
Node 而不是元素IDL里本身带的属性,通过NamedNodeMap
实现的(参见DOM 3 和 WHATWG)。因此对于IDL里没有name
的元素,不能直接用elem.name
获取name
,但用getAttribute
则都可以获取。例如:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div name="baz"></div> <a name="bar"></a> </body> </html>
在 console 里:
var div = document.getElementsByName(‘baz‘)[0]; div.name; // undefined div.getAttribute(‘name‘); // baz var a = document.getElementsByName(‘bar‘)[0]; a.name; // bar a.getAttribute(‘name‘); // bar
Document
继承 ContainerNode
(见WebCore/dom/Document.h),实质上使用了ContainerNode
的getElementsByName
。
ContainerNode
的getElementsByName
使用NameNodeList
作为NodeListsNodeData::addCacheWithAtomicName<>
的template specialization (见WebCore/dom/ContainerNode.cpp)。注意NodeListsNodeData::addCacheWithAtomicName<>
的模板提高了代码的重用——只需要为template specialization的类定义create
、elementMatches
等函数,即可使用addCacheWithAtomicName
实现live的NodeList的过滤+缓存。WebKit将这些函数都汇总在了CachedLiveNodeList
这个类里,只要继承这个类,实现它和它继承的虚函数,就可以用于addCacheWithAtomicName
的template specialization(参见WebCore/dom/LiveNodeList.h),建立一个带有缓存和特定过滤标准的NodeList。
NodeListsNodeData
使用一个私有的NodeListAtomicNameCacheMap
成员m_atomicNameCaches
实现缓存。当addCacheWithAtomicName
被调用时,首先检查是否已存在对应的缓存,若存在,用m_atomicNameCaches.fastAdd
快速更新(参见WebCore/dom/NodeRareData.h(注意NodeListAtomicNameCacheMap
本质上是一个hash map,参见typedef定义)。如果没有缓存,调用模版类的create
函数创建新的模版类对象并返回,这里为NameNodeList
。
NamedNodeList
继承 CachedLiveNodeList
,CachedLiveNodeList
的迭代器使用的collectionBegin()
,collectionTraverseForward()
等(见WebCore/dom/LiveNodeList.h)会遍历需要过滤的root node的后代,使用虚函数elementMatches
过滤(参见WebCore/dom/LiveNodeList.h)。NamedNodeList
实现的elementMatches
以element.getNameAttribute() == m_name
作为过滤标准(见WebCore/dom/NameNodeList.h)。
值得注意的是CachedLiveNodeList
的elementMatches
从LiveNodeList
继承而来,而在LiveNodeList
的原型里elementMatches
的原型为virtual bool elementMatches(Element&) const = 0
——仅仅是个虚函数,不需要inline(参见WebCore/dom/LiveNodeList.h),但是在NamedNodeList
的实现里这个函数被 inline 了。众所周知虚函数的调用要查表会带来较高的开销,对于这样会被高频率调用的函数来说显然是不行的,这里其实是通过 inline 来绕过这个开销。注意 virtual 与 inline 不冲突的条件是编译器需要在编译时知道将这个虚函数做inline实现的类是什么(而不能像普通的virtual调用一样留到运行时确定),而CachedLiveNodeList
里凡是调用elementMatches
的地方都会有类似auto& nodeList = static_cast<const NodeListType&>(*this)
的语句先利用模版确定自己的静态类型,然后再使用这个确定了静态类型的引用而不是this
来调用elementMatches
,所以不会冲突(这种写法名为Curiously Recurring Template Pattern,能够实现出所谓的static polymorphism来绕开虚函数调用的开销又达到虚函数调用的目的)。这样绕个大弯(用上模版)为虚函数添加 inline 通常是为了性能考虑,参见Stackoverflow上的相关问题,这里刚好符合应用场景——elementMatches
注定会被频繁调用。毕竟getElementsByName
经常会直接在document
上执行,那就会遍历文档里所有的节点,每遍历一个就要调用一次elementMatches
来过滤,那通常至少也是上百甚至上千上万的调用……同样地,在ElementDescendantIterator
里几乎所有的方法(包括构造函数)都被inline了,就是因为它作为遍历单位会被频繁调用方法,所以需要 inline 来榨干性能(参见WebCore/dom/ElementDescendantIterator.h
其他值得注意的点:
name
),用一个32位的整数来为ElementData
保存数组长度和flag(参见WebCore/dom/ElementData.h,,这样省空间又省时间,并且能够对IDL定义的属性和自定义的属性一视同仁。Node
里也是通过事先定义好的 flag 位运算来得知衍生类类型的(而不是使用C++昂贵的RTTI),flag的定义参见WebCore/dom/Node.hname
的元素,webkit实际上是包了一个element.getNameAttribute
来返回name
的,比如<a>
参见 WebCore/html/HTMLAnchorElement.cpp。因此NamedNodeList
的element.getNameAttribute()
不管name
在IDL里还是作为本身的属性都会一并将其返回,反映到上层就是getElementsByName()
也不需要管name
是否在IDL里。跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByName
标签:des style blog http io ar color 使用 sp
原文地址:http://www.cnblogs.com/joyeecheung/p/4115409.html