玩转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都 ...
随机推荐
- asp.net曲线图
highcharts的曲线图控件真的很强大,自己研究了下,做了一个简单的,给自己留个备忘,希望能帮到需要的朋友 Dome下载:http://files.cnblogs.com/linyijia/asp ...
- JS 拖动原理
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- JAVA会将所有的错误封装成为一个对象,其根本父类为Throwable
JAVA会将所有的错误封装成为一个对象,其根本父类为Throwable. Throwable有两个子类:Error和Exception. 一个Error对象表示一个程序错误,指的是底层的.低级的.不可 ...
- Worktile中百万级实时消息推送服务的实现
Worktile中百万级实时消息推送服务的实现 出自:http://blog.jobbole.com/81125/
- ThinkPHP项目笔记之数据库配置篇
对于配置文件,有几点说明 common:公共配置,也就是前台,后台,都可以调用的文件,具有普遍性 前台/后台:就是针对前后台的配置文件,具有针对性. 如:(公共文件基本配置) <?php ret ...
- wpf中用户控件的属性重用
我们经常会抽取一些可重用的控件,某个属性是否需要重用,直接决定了这个属性的绑定方式. 1.完全不可重用的控件 有一些与业务强相关的控件,它们的属性完全来自ViewModel,越是相对复杂的控件,越容易 ...
- python3----练习题(爬取电影天堂资源,大学排名,淘宝商品比价)
import requests import re url = 'http://www.ygdy8.net/html/gndy/dyzz/list_23_{}.html' for n in range ...
- Linux环境下Apache配置多个虚拟主机挂载多站点同时运行
博客地址: http://blog.csdn.net/ClydeKuo/article/details/69569474 这篇博客讲的很详细,很详细.
- [SharePoint 2010]Sandboxed Solution (沙箱解決方案)
現有的SharePoint 2007系統中,我們如果要安裝客製化的程式碼到系統中,我們必須製作一個解決方案包裝檔(Solution Package),然後在系統的中央管理後台中,真對整個伺服器農場Fa ...
- C#全角半角转换输出解决方法
Microsoft.VisualBasic 命名空间 Strings 模块 StrConv 函数就具有大写/小写.全角/半角.中文简体/繁体等转换功能,字符串转换应该说是VB.NET的强项,是这样的: ...