玩转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高级程序设计》
玩转DOM遍历——用NodeIterator实现getElementById,getElementsByTagName方法的更多相关文章
- DOM遍历
前面的话 DOM遍历模块定义了用于辅助完成顺序遍历DOM结构的类型:Nodeiterator和TreeWalker,它们能够基于给定的起点对DOM结构执行深度优先(depth-first)的遍历操作. ...
- JQuery总结:选择器归纳、DOM遍历和事件处理、DOM完全操作和动画 (转)
JQuery总结:选择器归纳.DOM遍历和事件处理.DOM完全操作和动画 转至元数据结尾 我们后台可能用到的页面一般都是用jquery取值赋值的,发现一片不错的文章 目录 JQuery总结一:选择器归 ...
- jQuery 源码分析(十九) DOM遍历模块详解
jQuery的DOM遍历模块对DOM模型的原生属性parentNode.childNodes.firstChild.lastChild.previousSibling.nextSibling进行了封装 ...
- getElementById() getElementsByTagName() getElementsByClassName() querySlector() querySlectorAll()区别
1. getElementById() getElementsByTagName() javascript原生的方法,这两个不会有兼容性问题. 2. getElementsByClassName() ...
- [DOM Event Learning] Section 1 DOM Event 处理器绑定的几种方法
[DOM Event Learning] Section 1 DOM Event处理器绑定的几种方法 网页中经常需要处理各种事件,通常的做法是绑定listener对事件进行监听,当事件发生后进行一 ...
- Jquery遍历筛选数组的几种方法和遍历解析json对象|Map()方法详解
Jquery遍历筛选数组的几种方法和遍历解析json对象|Map()方法详解 一.Jquery遍历筛选数组 1.jquery grep()筛选遍历数组 $().ready( function(){ v ...
- JQuery遍历json数组的3种方法
这篇文章主要介绍了JQuery遍历json数组的3种方法,本文分别给出了使用each.for遍历json的方法,其中for又分成两种形式,需要的朋友可以参考下 一.使用each遍历 $(functio ...
- Java遍历List集合的三种方法
Java遍历List集合的三种方法 List<String> list = new ArrayList<String>(); list.add("aaa") ...
- (转载)Java中如何遍历Map对象的4种方法
在Java中如何遍历Map对象 How to Iterate Over a Map in Java 在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都 ...
随机推荐
- 除去Scala的糖衣(13) -- Default Parameter Value
欢迎关注我的新博客地址:http://cuipengfei.me/ 好久没有写博客了,上一次更新竟然是一月份. 说工作忙都是借口,咋有空看美剧呢. 这半年荒废掉博客说到底就是懒,惯性的懒惰.写博客这事 ...
- 【BZOJ】1096: [ZJOI2007]仓库建设(dp+斜率优化)
http://www.lydsy.com/JudgeOnline/problem.php?id=1096 首先得到dp方程(我竟然自己都每推出了QAQ)$$d[i]=min\{d[j]+cost(j+ ...
- Python 资料性网站。
伯乐在线:http://blog.jobbole.com/category/python/ http://blog.chinaunix.net/uid/22334392/cid-24327-list- ...
- leetCode 77.Combinations (组合)
Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. For exampl ...
- hdu 3905(dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3905 思路:dp[i][j]表示前i分钟,睡了j分钟收获的的最大价值,并记tmp_dp[i][j]为从 ...
- WinError 5
IDE工具:pychrm 语言:python 在使用os模块修改路径名称时,总是会报 WinError 5 这个错误,就是拒绝访问,之前也遇见过,就是要操作的当前路径里有文件已经打开,代码不能再次访问 ...
- 怎样安装解压版MySQL
第一步: 解压包. 第二步:引入MySQL的bin路径. 第三步: 在cmd下敲入 mysqld -install 第四步:启动服务 net start mysql 第五步:空password登录 m ...
- Android之布局属性归纳
第一类:属性值为true或falseandroid:layout_centerHrizontal 水平居中android:layout_centerVertical 垂直居中android:layou ...
- ie8兼容:对象不支持“trim”属性或方法
trim() 方法是原生js中去空格的方法,高版本浏览器已经默认支持trim() 方法,但ie8以下不支持,会报错:对象不支持“trim”属性或方法 解决这个的兼容,只需要扩展String原型属性 在 ...
- AngularJS 解决 SEO 问题
由于 AngularJS 返回的是HTML模板,实际的内容需要执行JS以后才会填充进去,导致百度抓取蜘蛛抓不到,因此产生了 AngularJS 的 SEO 问题.经过几天的研究试验,我们的解决方案是这 ...