玩转DOM遍历——用NodeIterator实现getElementById,getElementsByTagName方法

先声明一下DOM2中NodeIterator和TreeWalker这两类型真的只是用来玩玩的,因为性能不行遍历起来超级慢,在JS中基本用不到它们,除了《高程》上有两三页对它的讲解外,谷歌的学习资料也是甚少(倒是有挺多国外文章)...由于本着不放过任何知识的态度,结合着自己的理解学习了下这两玩意,你们对这两东西了解了解就好~

DOM2级遍历和范围模块定义了两个用于完成顺序遍历DOM结构的类型:NodeIterator和TreeWalker。这两类型基于给定起点对DOM结构执行深度优先先序遍历,兼容性>IE8和高版本其他浏览器可访问。

NodeIterator:

使用document.createNodeIterator(root, whatShow, filter, entityReferenceExpansion)创建NoedIterator类型实例iterator,所以原型链关系为:
iterator.__proto__->NodeIterator.prototype->Object.prototye

TreeWalker:

使用document.createTreeWalker(root, whatShow, filter, entityReferenceExpansion)创建TreeWalker类型实例walker,所以原型链关系为:
walker.__proto__->TreeWalker.prototype->Object.prototype

对比下来,其实就两个方法常用,nextNode()和previousNode()。TreeWalker.prototype比NodeIterator.prototype多了一些在不同方向上遍历的方法也就没什么了。
(1).在每个iterator中有一个内部指针指向根节点,nextNode方法是返回遍历器内部指针所在节点,然后会将指针移向下一个节点。previousNode()方法是先将指针移向上一个节点,然后返回该节点。所以nextNode()==previousNode()

(2).在每个walker中也有一个内部指针,但是指向根节点的第一个子节点,nextNode方法是返回遍历器所在节点然后并不移动指针(就是说指针和节点在同一处),previous()方法是先将指针移向上一个节点,然后返回该节点,所以这里nextNode() != previous()

所以TreeWalker.prototype就有一个currentNode属性,表示在上一次遍历中返回的节点:

(3).区别说完,说说它两的参数都是相同的:
root:想要作为搜索起点的树中的节点
whatToShow:表示要访问哪些节点的数字代码,来自NodeFilter.prototype还是NodeFilter自身上中的这些大写常量...

filter:是NodeFilter类型实例对象,或者是一个表示应该接受还是拒绝某种特定节点的函数。作用是当调用nextNode或previousNode时候要经过这个过滤器来删选想要的节点,如果说文档中任何一个节点走一步,那么根据筛选节点类型不同每次返回的节点实际上可能走了好几步。
entityReferenceExpansion:表示是否要扩展实体引用,false就好。

对了,NodeIterator和TreeWalker还有一点区别就是在使用NodeIterator对象时,NodeFilter.FILTER_SKIP和NodeFilter.FILTER_REJECT作用相同跳过指定节点。在使用TreeWalker对象时,NodeFilter.FILTER_SKIP会跳过相应节点继续前进到子树中下一个节点,NodeFilter.FILTER_REJECT会相应节点及该节点的整个子树。

OK!说完了上面的,也不知道大家有没有懂~不懂没关系反正这两类型也不常用,效率也差~
通过DOM遍历的这两类型很容易让人想到我们常用的document.getElementById,document.getElementsByTagName,document.getElementsByNames...系列方法不是也是在DOM中搜寻指定节点的么...这里用NodeIterator来实现一下

Document.prototype.getElementById = function(id){
 var filter = function(node){
   return node.id == id ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
  }
 var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ELEMENT, filter, false);
 var node = iterator.nextNode();
 return node;
}

Document.prototype.getElementsByTagName = function(tagname){
 var filter = function(node){
     return node.tagName.toLowerCase() == tagname ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
  }
 var htmlcollection = [];
 var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ELEMENT, filter, false);
 var node = iterator.nextNode();
 while(node!=null){
   htmlcollection.push(node);
   node = iterator.nextNode();
 }
 htmlcollection.__proto__ = HTMLCollection.prototype;
 return htmlcollection;
}


成功!其他的方法类似的,感兴趣可以自行实现~

stackoverflow里有人提出了When to use NodeIterator? 把querySelector和filter过滤进行比较,这谁快谁慢光看名字就显而易见嘛,感兴趣可以看看啊~我粗略测试下

也不知道人家JS引擎中getElementById真正是怎么实现的,改天抽空看看~

参考

《JavaScript高级程序设计》

JavaScript标准参考教程-document节点

时间: 2024-10-25 07:36:06

玩转DOM遍历——用NodeIterator实现getElementById,getElementsByTagName方法的相关文章

DOM遍历

前面的话 DOM遍历模块定义了用于辅助完成顺序遍历DOM结构的类型:Nodeiterator和TreeWalker,它们能够基于给定的起点对DOM结构执行深度优先(depth-first)的遍历操作.本文将详细介绍DOM遍历 [注意]IE8-浏览器不支持 定义 DOM遍历是深度优先的DOM结构遍历,遍历以给定节点为根,不可能向上超出DOM树的根节点.以下面的HTML页面为例 <!DOCTYPE html> <html> <head> <title>Examp

用PHP代替JS玩转DOM

事情的起源比较简单,我需要把一个导航页的数据整理好写入数据库.一个比较直观的方法是对html文件进行分析,通用的方法是用php的正则表达式来匹配.但是这样做开发和维护都很困难,代码可读性非常差. 导航页的数据都是规则的排列在DOM树当中的,用JS可以用几个循环轻松的对其进行操作,而且JS需要依赖浏览器,操作数据库很困难.其实PHP就有现成的类库对DOM树种的节点进行增删改查操作,在此做一些笔记. 这里涉及到2个类 DOMDocument 和 DOMXPath. 其实思路比较明确,就是通过DOMD

JavaScript框架探索4——DOM遍历2

接着上篇的话题继续,原生的js中有两种循环,分别是普通的for循环和for in循环,不管是哪种循环我们使用它们的时候经常有的一个操作就是循环遍历某一项,然后执行很多动作,在这些动作中如果遇到上篇中的给某个对象添加方法(或事件,事实上事件就是特殊的方法)的时候就会引起共享外部作用域的问题: var arr = [1, 2, 3]; var obj = {}; for(var i = 0; i < arr.length; i++){ aDiv[i].onclick = function(){ co

JQuery总结:选择器归纳、DOM遍历和事件处理、DOM完全操作和动画

JQuery总结一:选择器归纳 1.基本选择器 选择符 匹配元素 * 所有元素 id 给定ID的元素 element 给定类型的所有元素 .class 给定类的所有元素 a,b 与a或b匹配的元素 a b a的后代元素中与b匹配的元素 a>b a的直接子元素中与b匹配的元素 a+b a的直接同辈元素中与b匹配的元素 a~b a的同辈元素中与b匹配的元素 2.位置选择器 选择符 匹配元素 a b:nth-child(index) a的子元素中,第index个与b匹配的元素(从1开始计数) a b:

DOM遍历节点以及属性

一.遍历DOM节点 遍历DOM节点常用一般用节点的 childNodes, firstChild, lastChild, nodeType, nodeName, nodeValue属性.在获取节点nodeValue时要注意,元素节点的子文本节点的nodeValue才是元素节点中文本的内容. 二.遍历节点属性 Element类型是使用attributes属性的唯一一个DOM节点类型.attributes属性中包含一个NamedNodeMap(节点属性列表).NamedNodeMap对象拥有下列方法

XML DOM 遍历Xml文档

1.xml文档内容: <?xml version="1.0" encoding="utf-8" ?> <bookstore> <book category="children"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>200

DOM遍历方法(基于jQuery)

在使用$()创建了jQuery对象之后,通过调用下列DOM遍历方法,可以修改其中匹配的元素,以便将来操作. 筛选元素 .filter(selector)                              与给定的选择符selector匹配的选中元素 .filter(callback)                              回调函数callback返回true的选中元素 .eq(index)                                     从0开

jQuery 源码分析(十九) DOM遍历模块详解

jQuery的DOM遍历模块对DOM模型的原生属性parentNode.childNodes.firstChild.lastChild.previousSibling.nextSibling进行了封装和扩展,用于在DOM树中遍历父元素.子元素和兄弟元素. 可以通过jQuery的实例来访问,方法如下: parent()             ;获取匹配元素的父元素 parents(selector)         ;获取匹配元素的所有祖先元素                        ;s

DOM中document对象的常用属性方法总结

提要: 每个载入浏览器的 HTML 文档都会成为 Document 对象. Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问 1.常见对象属性 document.title                 //设置文档标题等价于HTML的<title>标签document.bgColor               //设置页面背景色document.fgColor               //设置前景色(文本颜色)document.linkColor