玩转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都 ...
随机推荐
- 重新=》easyui DataGrid是否可以动态的改变列显示的顺序
$.extend($.fn.datagrid.methods,{ columnMoving: function(jq){ return jq.each(function(){ var target = ...
- [JS] jquery控件基本要点备份
(1)CDN Google CDN:<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min. ...
- C++ 类的继承二(赋值兼容性原则)
//赋值兼容性原则 #include<iostream> using namespace std; class PointA{ public: PointA(){ x = ; y = ; ...
- 关于Unity中的transform组件(一)
一.transform组件用途 1.维护场景树 2.对3D物体的平移,缩放,旋转 二.场景树定义 在Hierarchy视图中显示的: 一个game_scene场景,下面有Main Camera节点,D ...
- 【BZOJ】1637: [Usaco2007 Mar]Balanced Lineup(前缀和+差分+特殊的技巧)
http://www.lydsy.com/JudgeOnline/problem.php?id=1637 很神思想.. 前缀和应用到了极点... 我们可以发现当数量一定时,这个区间最前边的牛的前边一个 ...
- sdut 面向对象程序设计上机练习十(运算符重载)
面向对象程序设计上机练习十(运算符重载) Time Limit: 1000MS Memory limit: 65536K 题目描写叙述 定义一个复数类Complex,重载运算符"+" ...
- C# 创建XML文件
private void CreateXMLFile(string pathAndFileName) { XmlDocument doc = new XmlDocument(); XmlElement ...
- iOS 功能代码 上传到 远程 码云私有库
推送代码到远程私有库 创建私有库(注意:仓库名称LYDKit必须和本地仓库对应的名称一样) 复制远程仓库的地址,打开终端,cd到对应的本地库路径下面 >>> cd /Users/cx ...
- Firefox 新增容器标签:可同时登录多个用户
Mozilla昨天在Firefox夜间构建版50.0a1中增加了一个名为“容器标签Container Tabs”的实验性功能. Mozilla的工程师称,该功能可以将用户的浏览会话分到不同的容器中.这 ...
- EditText监听方法,实时的判断输入多少字符
最近在写一个小项目,其中有一点用到了显示EditText中输入了多少个字符,像微博中显示剩余多少字符的功能.在EditText提供了一个方法addTextChangedListener实现对输入文本的 ...