jQuery源码分析-11 DOM遍历-Traversing-DOM遍历方法
2014-10-11 16:46
826 查看
作者:nuysoft/高云 QQ:47214707 Email:nuysoft@gmail.com
声明:本文为原创文章,如需转载,请注明来源并保留原文链接。
jQuery源码分析系列(持续更新)
1. 属性childNodes vs 属性children
2. 方法children vs 方法contents
3. 完整源码分析(亮点在排序、去重部分)
声明:本文为原创文章,如需转载,请注明来源并保留原文链接。
jQuery源码分析系列(持续更新)
1. 属性childNodes vs 属性children
childNodes | Retrieves a collection of HTML Elements and TextNode objects that are direct descendants of the specified object. 标准,包含HTML元素、文本 |
children | Retrieves a collection of DHTML Objects that are direct descendants of the object. 非标准,只包含HTML元素 |
jQuery.fn.children( elem ) | 只包含Element |
jQuery.fn.contents( elem ) | 包含Element、Text、Comment |
jQuery.each({ parent: function( elem ) { // 父元素 var parent = elem.parentNode; return parent && parent.nodeType !== 11 ? parent : null; // DocumentFragment 11, DocumentType 10 }, parents: function( elem ) { // 祖先元素 return jQuery.dir( elem, "parentNode" ); // 检索所有父元素,直至document }, parentsUntil: function( elem, i, until ) { // return jQuery.dir( elem, "parentNode", until ); }, next: function( elem ) { // 下一个兄弟元素 return jQuery.nth( elem, 2, "nextSibling" ); // 从1开始计数,当前是第1个,为什么要再搞一套不一致的索引方法呢? }, prev: function( elem ) { // 上一个兄长元素 return jQuery.nth( elem, 2, "previousSibling" ); }, nextAll: function( elem ) { // 所有的兄弟元素 return jQuery.dir( elem, "nextSibling" ); }, prevAll: function( elem ) { // 所有的兄长元素 return jQuery.dir( elem, "previousSibling" ); }, nextUntil: function( elem, i, until ) { // 所有的兄弟元素,但是不包括until return jQuery.dir( elem, "nextSibling", until ); }, prevUntil: function( elem, i, until ) { // 所有的兄长元素,但是不包括until return jQuery.dir( elem, "previousSibling", until ); }, siblings: function( elem ) { // 所有兄长、兄弟元素,不包括当前元素 return jQuery.sibling( elem.parentNode.firstChild, elem ); // 父元素的第一个子元素的所有兄弟元素,排除当前元素elem // 取子元素childNodes然后过滤elem,效率更高 }, children: function( elem ) { // 所有的子节点,只包含Element return jQuery.sibling( elem.firstChild ); // 第一个子元素的所有兄弟元素 // 为什么不直接取子元素呢?childNodes不是效率更高么? }, contents: function( elem ) { // 所有的子节点,包含Element、Text、Comment return jQuery.nodeName( elem, "iframe" ) ? elem.contentDocument || elem.contentWindow.document : // 如果是iframe,则取document jQuery.makeArray( elem.childNodes ); // 将childNodes转换数组,childNodes是伪数组,转换后遍历数组时可以避免对childNodes进行检查,提高性能 } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { var ret = jQuery.map( this, fn, until ), // 将this中的元素,用fn处理,最后返回真正的数组,until用于过滤 // The variable 'args' was introduced in // https://github.com/jquery/jquery/commit/52a0238 // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. // http://code.google.com/p/v8/issues/detail?id=1050 args = slice.call(arguments); // 将arguments复制并转为数组 if ( !runtil.test( name ) ) { // 不以Until结尾 selector = until; // 不需要参数until,只有一个参数selector,util只到这里为止 } if ( selector && typeof selector === "string" ) { ret = jQuery.filter( selector, ret ); // 对ret数组用selector进行过滤,只留下匹配的元素 // jQuery.filter会调用jQuery.find.matches > Sizzle.matches > Sizzle,Sizzle查找、过滤的结果已经经过排序、去重 } /** * 排序、去重 * 首先要知道this是经过排序、且无重复 * 如果长度大于1,才需要判断是否需要去重 * 如果name是 children contents next prev 之一,则不需要排序去重,因为这四个方法不会产生无序和重复的结果,为什么呢? * 因为this中的元素是有序、去重的,所以的它子节点、兄弟、兄长,也都是有序、无重复的 * 但是parent parents parentsUntil nextAll prevAll nextUntil prevUntil siblings却有可能产生重复、无序的元素 * * 可见这里进行了优化,不可否则这种编码习惯很精致很赞,但是: * 即使不需要排序、去重的情况,也必然要经过这些漫长的判断,就是一种浪费 * 这种多功能导致的复杂性和无谓的性能消耗,在jQuery中随处可见 * 虽然没有做详尽的性能测试,其实也没必要,但稍微给我有点“机关算尽太聪明,枉费了卿卿性命”的感觉 * 从刚开始读源码时的惊艳和崇拜,渐渐的能分辨其中的精髓与作者的权衡拿捏,jQuery的伟大不可否认, * 但是我们写代码的时候,要借鉴参考,也要思考取舍 * * 上边的感触仅供参考,我还处于能读懂和能分析jQuery源码的阶段,不到自创一套类库的境界, * 也许水平提高了jQuery不能满足我的时候,再回头看,兴许是另一重感悟了。 */ ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; // 去重 // rparentsprev = /^(?:parents|prevUntil|prevAll)/ // 因为前边返回的结果是按照元素在文档中的位置顺序返回的,遇到rparentsprev则需要再反过来,方便使用 if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { ret = ret.reverse(); // 倒序 } return this.pushStack( ret, name, args.join(",") ); // 构造jQuery对象 }; }) |
相关文章推荐
- [原创] jQuery源码分析-11 DOM遍历-Traversing-DOM遍历方法
- [原创] jQuery源码分析-11 DOM遍历-Traversing-3个核心函数
- jQuery源码分析-11 DOM遍历-Traversing-3个核心函数
- jQuery源码分析系列:DOM遍历方法
- jQuery实现DOM加载方法源码分析
- jQuery 源码分析和使用心得 - 文档遍历 ( traversing.js )
- jQuery 遍历- 关于closest() 的方法介绍以及与parents()的方法区别分析
- Javascript笔记:jQuery源码分析以及从jQuery对象创建的角度理解extend方法的原理
- jQuery插件-jRating评分插件源码分析及使用方法
- jQuery基础教程之DOM操作-遍历节点-parents()方法
- [原创] jQuery源码分析-12 DOM操作-Manipulation-核心函数jQuery.buildFragment()
- jQuery基础教程之DOM操作-遍历节点-next()方法
- jQuery源码分析系列:Extend扩展方法
- jQuery基础教程之DOM操作-遍历节点-find()方法
- jQuery 遍历- 关于closest() 的方法介绍以及与parents()的方法区别分析
- jQuery基础教程之DOM操作-遍历节点-children()方法
- Javascript笔记:(实践篇)从jQuery插件技术说起-分析extend方法的源码(发现extend方法里有bug)(下篇)
- jquery源码阅读知识储备(11)数学方法(四舍五入)
- [原创] jQuery源码分析-12 DOM操作-Manipulation-核心函数.domManip()
- learning jQuery 学习笔记二(+jQuery 1.4.1 API)--DOM遍历方法