jQuery技术内幕:深入解析jQuery架构设计与实现原理. 3.10 工具方法

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介:

3.10 工具方法

3.10.1 Sizzle.uniqueSort( results )

工具方法Sizzle.uniqueSort( results )负责对元素集合中的元素按照出现在文档中的顺序进行排序,并删除重复元素。

相关代码如下所示:

4026 Sizzle.uniqueSort = function( results ) {

4027     if ( sortOrder ) {

4028         hasDuplicate = baseHasDuplicate;

4029         results.sort( sortOrder );

4030

4031         if ( hasDuplicate ) {

4032             for ( var i = 1; i < results.length; i++ ) {

4033                 if ( results[i] === results[ i - 1 ] ) {

4034                     results.splice( i--, 1 );

4035                 }

4036             }

4037         }

4038     }

4039

4040     return results;

4041 };

第4029行:调用数组方法sort()对数组中的元素进行排序。其中,sortOrder( a, b )是比较函数,负责比较元素a和元素b在文档中的位置。如果比较函数sortOrder( a, b )遇到相等的元素,即重复元素,会设置变量hasDuplicate为true。关于比较函数sortOrder( a, b )的具体说明请参见3.10.2节。

第4031~4037行:如果变量hasDuplicate为true,表示存在重复元素,则遍历数组results,比较相邻元素是否相等,如果相等则删除。

第4028行:开始排序和去重时,先设置变量hasDuplicate的默认值为变量baseHas

Duplicate,变量baseHasDuplicate指示了JavaScript引擎在排序时是否会进行优化。

相关代码如下所示:

3864     hasDuplicate = false,

3865     baseHasDuplicate = true,

 

3870 // Here we check if the JavaScript engine is using some sort of

3871 // optimization where it does not always call our comparision

3872 // function. If that is the case, discard the hasDuplicate value.

3873 // Thus far that includes Google Chrome.

3874 [0, 0].sort(function() {

3875     baseHasDuplicate = false;

3876     return 0;

3877 });

第3874~3877行:检查JavaScript引擎在排序时是否会进行优化。在早期的Chrome浏览器中,排序时如果遇到相等的元素,不会调用比较函数,新版本中已经取消了这一优化。如果遇到相等元素便不调用比较函数,此时变量baseHasDuplicate默认为true,即只能假设数组中含有重复元素;如果遇到相等元素时仍然会调用比较函数,则变量baseHasDuplicate将被设置为false,这种情况下需要在比较函数中判断是否含有重复元素。

读者可以访问http://bugs.jquery.com/ticket/5380查看该bug的描述。

3.10.2 sortOrder( a, b )

函数sortOrder( a, b )负责比较元素a和元素b在文档中的位置。如果元素a在元素b之前,则返回-1;如果元素a在元素b之后,则返回1;如果元素a与元素b相等,则返回0。

函数sortOrder( a, b )通过调用原生方法compareDocumentPosition()或比较原生属性source

Index来实现。原生方法compareDocumentPosition()用于比较两个元素的文档位置;原生属性sourceIndex则返回元素在文档中的序号,返回值等于该元素在document.getElementsBy

TagName('*')返回的数组中的下标。更多信息请访问http://www.quirksmode.org/dom/w3c_core.html。

函数sortOrder( a, b )执行的3个关键步骤如下:

1)如果浏览器支持原生方法compareDocumentPosition(),则调用该方法比较元素位置。

2)如果浏览器支持原生属性sourceIndex,则用该属性比较元素位置。

3)否则比较祖先元素的文档位置。

下面来看看该函数的源码实现。

1.?浏览器支持原生方法compareDocumentPosition()的情况

如果浏览器支持原生方法compareDocumentPosition(),则调用该方法比较元素位置。相关代码如下所示:

4805 var sortOrder, siblingCheck;

4806

4807 if ( document.documentElement.compareDocumentPosition ) {

4808     sortOrder = function( a, b ) {

4809        if ( a === b ) {

4810            hasDuplicate = true;

4811            return 0;

4812        }

4813

4814        if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {

4815           return a.compareDocumentPosition ? -1 : 1;

4816        }

4817

4818        return a.compareDocumentPosition(b) & 4 ? -1 : 1;

4819     };

4820

2.?浏览器支持原生属性sourceIndex的情况

如果浏览器支持原生属性sourceIndex,则用该属性比较元素位置。

相关代码如下所示:

4821 } else {

4822     sortOrder = function( a, b ) {

4823         // The nodes are identical, we can exit early

4824         if ( a === b ) {

4825            hasDuplicate = true;

4826            return 0;

4827

4828         // Fallback to using sourceIndex (in IE) if it's available on both nodes

4829         } else if ( a.sourceIndex && b.sourceIndex ) {

4830             return a.sourceIndex - b.sourceIndex;

4831         }

4832

3.否则比较祖先元素的文档位置

(1)元素a和元素b是兄弟元素的情况

相关代码如下所示:

4833         var al, bl,

4834             ap = [],

4835             bp = [],

4836             aup = a.parentNode,

4837             bup = b.parentNode,

4838             cur = aup;

4839

4840         // If the nodes are siblings (or identical) we can do a quick check

4841         if ( aup === bup ) {

4842             return siblingCheck( a, b );

4843

第4836~4837行、第4841~4842行:变量aup是元素a的父元素,变量bup是元素b的父元素。如果变量aup与变量bup相等,说明元素a和元素b是兄弟元素,则调用函数siblingCheck()比较元素a和元素b的文档位置。函数siblingCheck( a, b, ret )负责比较兄弟元素的文档位置,稍后会看到该函数的源码实现和分析。

(2)没有找到父元素的情况

相关代码如下所示:

4844         // If no parents were found then the nodes are disconnected

4845         } else if ( !aup ) {

4846             return -1;

4847

4848         } else if ( !bup ) {

4849             return 1;

4850         }

4851

第4845~4850行:如果元素a没有父元素,则认为元素a不在文档中,返回-1,元素a将排在元素b之前;如果元素b没有父元素,则认为元素b不在文档中,返回1,元素b将排在元素a之前。

(3)查找元素a和元素b的祖先元素

相关代码如下所示:

4852         // Otherwise they're somewhere else in the tree so we need

4853         // to build up a full list of the parentNodes for comparison

4854         while ( cur ) {

4855             ap.unshift( cur );

4856             cur = cur.parentNode;

4857         }

4858

4859         cur = bup;

4860

4861         while ( cur ) {

4862             bp.unshift( cur );

4863             cur = cur.parentNode;

4864         }

4865

(4)比较祖先元素的文档位置

相关代码如下所示:

4866         al = ap.length;

4867         bl = bp.length;

4868

4869         // Start walking down the tree looking for a discrepancy

4870         for ( var i = 0; i < al && i < bl; i++ ) {

4871             if ( ap[i] !== bp[i] ) {

4872                 return siblingCheck( ap[i], bp[i] );

4873             }

4874         }

4875

第4866~4874行:从最顶层的祖先元素开始向下遍历,如果祖先元素ap[i]与bp[i]不是同一个元素,那么它们必然是兄弟元素,此时可以通过比较两个祖先元素的文档位置,来确定元素a和元素b的相对位置。

(5)元素a和元素b的文档深度不一致的情况

相关代码如下所示:

4876         // We ended someplace up the tree so do a sibling check

4877         return i === al ?

4878             siblingCheck( a, bp[i], -1 ) :

4879             siblingCheck( ap[i], b, 1 );

4880     };

4881

第4877~4878行:如果元素a的文档深度较小,此时元素a与元素b的祖先元素bp[i]要么是兄弟元素,要么是同一个元素,可以调用函数siblingCheck( a, b, ret )比较文档位置。

第4877~4879行:如果元素b的文档深度较小,此时元素a的祖先元素ap[i]与元素b要么是兄弟元素,要么是同一个元素,可以调用函数siblingCheck( a, b, ret )比较文档位置。

(6)siblingCheck( a, b, ret )

函数siblingCheck( a, b, ret )负责比较兄弟元素的文档位置。该函数从元素a向后遍历(nextSibling),如果遇到元素b,说明元素a在元素b之前,则返回-1;如果一直没遇到,说明元素a在元素b之后,则返回1。

相关代码如下所示:

4882     siblingCheck = function( a, b, ret ) {

4883         if ( a === b ) {

4884             return ret;

4885         }

4886

4887         var cur = a.nextSibling;

4888

4889         while ( cur ) {

4890             if ( cur === b ) {

4891                 return -1;

4892             }

4893

4894             cur = cur.nextSibling;

4895         }

4896

4897         return 1;

4898     };

4899 }

3.10.3 Sizzle.contains( a, b )

工具方法Sizzle.contains( a, b )负责检测元素a是否包含元素b。该方法通过调用原生方法contains()或compareDocumentPosition()实现。原生方法contains()用于检测一个元素是否包含另一个元素;原生方法compareDocumentPosition()用于比较两个元素的文档位置,更多信息请访问以下网址:

http://ejohn.org/blog/comparing-document-position/

http://www.quirksmode.org/dom/w3c_core.html#miscellaneous

相关代码如下所示:

5242 if ( document.documentElement.contains ) {

5243     Sizzle.contains = function( a, b ) {

5244        return a !== b && (a.contains ? a.contains(b) : true);

5245     };

5246

5247 } else if ( document.documentElement.compareDocumentPosition ) {

5248     Sizzle.contains = function( a, b ) {

5249        return !!(a.compareDocumentPosition(b) & 16);

5250     };

5251

5252 } else {

5253     Sizzle.contains = function() {

5254        return false;

5255     };

5256 }

3.10.4 Sizzle.error( msg )

工具方法Sizzle.error( msg )用于抛出一个含有选择器表达式语法错误信息的异常。

相关代码如下所示:

4178 Sizzle.error = function( msg ) {

4179     throw new Error( "Syntax error, unrecognized expression: " + msg );

4180 };

3.10.5 Sizzle.getText( elem )

工具方法Sizzle.getText( elem )用于获取元素集合中所有元素合并后的文本内容。

相关代码如下所示:

4182 /**

4183 * Utility function for retreiving the text value of an array of DOM nodes

4184 * @param {Array|Element} elem

4185 */

4186 var getText = Sizzle.getText = function( elem ) {

4187     var i, node,

4188         nodeType = elem.nodeType,

4189         ret = "";

4190

4191     if ( nodeType ) {

4192         if ( nodeType === 1 || nodeType === 9 ) {

4193             // Use textContent || innerText for elements

4194             if ( typeof elem.textContent === 'string' ) {

4195                 return elem.textContent;

4196             } else if ( typeof elem.innerText === 'string' ) {

4197                 // Replace IE's carriage returns

4198                 return elem.innerText.replace( rReturn, '' );

4199             } else {

4200                 // Traverse it's children

4201                 for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {

4202                     ret += getText( elem );

4203                 }

4204             }

4205         } else if ( nodeType === 3 || nodeType === 4 ) {

4206             return elem.nodeValue;

4207         }

4208     } else {

4209

4210         // If no nodeType, this is expected to be an array

4211         for ( i = 0; (node = elem[i]); i++ ) {

4212             // Do not traverse comment nodes

4213             if ( node.nodeType !== 8 ) {

4214                 ret += getText( node );

4215             }

4216         }

4217     }

4218     return ret;

4219 };

第4191~4207行:如果参数elem是元素,则尝试读取属性textContent或innerText,如果不支持则遍历子元素,递归调用工具函数getText( elem )来获取每个子元素的文本内容,并合并;如果参数elem是Text节点或CDATASection节点,则直接返回节点值nodeValue。

第4208~4217行:否则认为参数elem是元素集合,遍历该元素集合,递归调用函数getText(elem)获取每个元素的文本内容,并合并。

第4218行:最后返回合并后的文本内容。

相关文章
|
10天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
51 6
|
10天前
|
设计模式 Java API
微服务架构演变与架构设计深度解析
【11月更文挑战第14天】在当今的IT行业中,微服务架构已经成为构建大型、复杂系统的重要范式。本文将从微服务架构的背景、业务场景、功能点、底层原理、实战、设计模式等多个方面进行深度解析,并结合京东电商的案例,探讨微服务架构在实际应用中的实施与效果。
27 1
|
5天前
|
SQL Java 数据库连接
Mybatis架构原理和机制,图文详解版,超详细!
MyBatis 是 Java 生态中非常著名的一款 ORM 框架,在一线互联网大厂中应用广泛,Mybatis已经成为了一个必会框架。本文详细解析了MyBatis的架构原理与机制,帮助读者全面提升对MyBatis的理解和应用能力。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Mybatis架构原理和机制,图文详解版,超详细!
|
11天前
|
Kubernetes Cloud Native 云计算
云原生技术深度解析:重塑企业IT架构的未来####
本文深入探讨了云原生技术的核心理念、关键技术组件及其对企业IT架构转型的深远影响。通过剖析Kubernetes、微服务、容器化等核心技术,本文揭示了云原生如何提升应用的灵活性、可扩展性和可维护性,助力企业在数字化转型中保持领先地位。 ####
|
11天前
|
自然语言处理 并行计算 数据可视化
免费开源法律文档比对工具:技术解析与应用
这款免费开源的法律文档比对工具,利用先进的文本分析和自然语言处理技术,实现高效、精准的文档比对。核心功能包括文本差异检测、多格式支持、语义分析、批量处理及用户友好的可视化界面,广泛适用于法律行业的各类场景。
|
12天前
|
运维 Kubernetes Cloud Native
Kubernetes云原生架构深度解析与实践指南####
本文深入探讨了Kubernetes作为领先的云原生应用编排平台,其设计理念、核心组件及高级特性。通过剖析Kubernetes的工作原理,结合具体案例分析,为读者呈现如何在实际项目中高效部署、管理和扩展容器化应用的策略与技巧。文章还涵盖了服务发现、负载均衡、配置管理、自动化伸缩等关键议题,旨在帮助开发者和运维人员掌握利用Kubernetes构建健壮、可伸缩的云原生生态系统的能力。 ####
|
15天前
|
机器学习/深度学习 人工智能 自然语言处理
医疗行业的语音识别技术解析:AI多模态能力平台的应用与架构
AI多模态能力平台通过语音识别技术,实现实时转录医患对话,自动生成结构化数据,提高医疗效率。平台具备强大的环境降噪、语音分离及自然语言处理能力,支持与医院系统无缝集成,广泛应用于门诊记录、多学科会诊和急诊场景,显著提升工作效率和数据准确性。
|
6天前
|
存储 供应链 物联网
深入解析区块链技术的核心原理与应用前景
深入解析区块链技术的核心原理与应用前景
|
6天前
|
存储 供应链 安全
深度解析区块链技术的核心原理与应用前景
深度解析区块链技术的核心原理与应用前景
13 0
|
Web App开发 JavaScript 前端开发

推荐镜像

更多