jquery构造器的实现代码小结

显然,能做到这一步,其实现是相当的复杂,这个实现就是它的init方法,jQuery的真实构造器。它功能也随着版本的升级而升级,越来越长。
2009-01-13发布的1.3版


代码如下:

init: function( selector, context ) {
// Make sure that a selection was provided
selector = selector || document;
// 处理节点参数,直接添加属性到新实例上
if ( selector.nodeType ) {
this[0] = selector;
this.length = 1;
this.context = selector;
return this;
}
// 处理字符串参数
if ( typeof selector === "string" ) {
// 判定是否为HTML片断还是ID
var match = quickExpr.exec( selector );
if ( match && (match[1] || !context) ) {
// 如果是HTML片断,转换一个由节点构造的数组
if ( match[1] )
selector = jQuery.clean( [ match[1] ], context );
// 如果是ID,则查找此元素,如果找到放进空数组中
else {
var elem = document.getElementById( match[3] );
// Make sure an element was located
if ( elem ){
// 处理 IE and Opera 混淆ID与NAME的bug
if ( elem.id != match[3] )
return jQuery().find( selector );
var ret = jQuery( elem );
ret.context = document;
ret.selector = selector;
return ret;
}
selector = [];
}
} else
//使用Sizzle处理其他CSS表达式,生成实例并返回
return jQuery( context ).find( selector );
// 处理函数参数,直接domReady
} else if ( jQuery.isFunction( selector ) )
return jQuery( document ).ready( selector );
//处理jQuery对象参数,简单地将其两个属性赋给新实例
if ( selector.selector && selector.context ) {
this.selector = selector.selector;
this.context = selector.context;
}
//将上面得到节点数组,用setArray方法把它们变成实例的元素
return this.setArray(jQuery.makeArray(selector));
},

2009-02-19发布的1.32版


代码如下:

init: function( selector, context ) {
// Make sure that a selection was provided
selector = selector || document;
// 处理节点参数,直接添加属性到新实例上
if ( selector.nodeType ) {
this[0] = selector;
this.length = 1;
this.context = selector;
return this;
}
//处理字符串参数
if ( typeof selector === "string" ) {
//判定是否为HTML片断还是ID
var match = quickExpr.exec( selector );
if ( match && (match[1] || !context) ) {
// 如果是HTML片断,转换一个由节点构造的数组
if ( match[1] )
selector = jQuery.clean( [ match[1] ], context );
else {
var elem = document.getElementById( match[3] );
// 如果是ID,则查找此元素,如果找到放进空数组中
if ( elem && elem.id != match[3] )
return jQuery().find( selector );
//这里对1.3版做了些优化,更简洁
var ret = jQuery( elem || [] );
ret.context = document;
ret.selector = selector;
return ret;
}
} else
//使用Sizzle处理其他CSS表达式,生成实例并返回
return jQuery( context ).find( selector );
// 处理函数参数,进行domReady操作
} else if ( jQuery.isFunction( selector ) )
return jQuery( document ).ready( selector );
//处理jQuery对象参数,简单地将其两个属性赋给新实例
if ( selector.selector && selector.context ) {
this.selector = selector.selector;
this.context = selector.context;
}
//这里对1.3版做了些扩展,允许传珍上元素集合(HTMLCollection)与节点集合(NodeList),
//元素数组可能是我们用字符串转换过来的,也可以是用户直接传进来的
return this.setArray(jQuery.isArray( selector ) ? selector : jQuery.makeArray(selector));
},

2010-01-13发布的1.4版


代码如下:

init: function( selector, context ) {
var match, elem, ret, doc;
//处理空白字符串,null,undefined参数(新增),返回一个非常纯净的实例
if ( !selector ) {
return this;
}
// 处理节点参数,直接添加属性到新实例上
if ( selector.nodeType ) {
this.context = this[0] = selector;//写法上优化
this.length = 1;
return this;
}
//处理字符串参数
if ( typeof selector === "string" ) {
// 判定是否为HTML片断还是ID
match = quickExpr.exec( selector );
if ( match && (match[1] || !context) ) {
//如果是HTML片断
if ( match[1] ) {
//取得文档对象
doc = (context ? context.ownerDocument || context : document);
// 如果是单个标签,直接使用 document.createElement创建此节点并放入数组中
ret = rsingleTag.exec( selector );
if ( ret ) {
//如果后面跟着一个纯净的JS对象,则为此节点添加相应的属性或样式
if ( jQuery.isPlainObject( context ) ) {
selector = [ document.createElement( ret[1] ) ];
jQuery.fn.attr.call( selector, context, true );
} else {
selector = [ doc.createElement( ret[1] ) ];
}
} else {
//改由buildFragment来生成节点集合(NodeList)
ret = buildFragment( [ match[1] ], [ doc ] );
selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
}
} else {
// 如果是ID,则查找此元素,如果找到放进空数组中
elem = document.getElementById( match[2] );
if ( elem ) {
// 处理 IE and Opera 混淆ID与NAME的bug
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}
//这里也做了一些优化,原来是很傻地再生成一个jQuery实例
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
}
// 如果字符是很简单的标签选择器,那基本没有必要走Sizzle路线,直接getElementsByTagName,很好的优化
} else if ( !context && /^\w+$/.test( selector ) ) {
this.selector = selector;
this.context = document;
selector = document.getElementsByTagName( selector );
// 如果第二个参数不存在或者是jQuery对象,那么用它或rootjQuery调用find查找目标节点(走Sizzle路线)
} else if ( !context || context.jquery ) {
return (context || rootjQuery).find( selector );
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
//如果第二个参数已指定为某元素节点,转为jQuery对象,走Sizzle路线
return jQuery( context ).find( selector );
}
// 处理函数参数,直接domReady
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
//处理jQuery对象参数,简单地将其两个属性赋给新实例
if (selector.selector !== undefined) {
this.selector = selector.selector;
this.context = selector.context;
}
//这里又做了些许修改,缘于makeArray可以接受第二个参数(可以是数组或类数组,这时相当合并操作)
return jQuery.isArray( selector ) ?
this.setArray( selector ) ://内部用push方法,迅速将一个普通对象变成类数组对象
jQuery.makeArray( selector, this );
},

接着是广受欢迎的2010-02-13发布的1.42版


代码如下:

init: function( selector, context ) {
var match, elem, ret, doc;
// 处理空白字符串,null,undefined参数
if ( !selector ) {
return this;
}
// 处理节点参数
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
}
// 处理body参数(新增)
if ( selector === "body" && !context ) {
this.context = document;
this[0] = document.body;
this.selector = "body";
this.length = 1;
return this;
}
// 处理字符串参数,分七种情形:
//①单个标签,带对象属性包 ---> jQuery.merge
//②单个标签,不带对象属性包 ---> attr + jQuery.merge
//③复杂的HTML片断 ---> buildFragment + jQuery.merge
//④ID选择器,与找到的元素的ID不同 ---> getElementById + Sizzle + pushStack
//⑤ID选择器,与找到的元素的ID相同 ---> getElementById + 简单属性添加
//⑥标签选择器 ---> getElementsByTagName + jQuery.merge
//⑦其他CSS表达式 ---> Sizzle + pushStack
if ( typeof selector === "string" ) {
match = quickExpr.exec( selector );
if ( match && (match[1] || !context) ) {
if ( match[1] ) {
doc = (context ? context.ownerDocument || context : document);
ret = rsingleTag.exec( selector );
if ( ret ) {
if ( jQuery.isPlainObject( context ) ) {
selector = [ document.createElement( ret[1] ) ];
jQuery.fn.attr.call( selector, context, true );
} else {
selector = [ doc.createElement( ret[1] ) ];
}
} else {
ret = buildFragment( [ match[1] ], [ doc ] );
selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
}
return jQuery.merge( this, selector );
} else {
elem = document.getElementById( match[2] );
if ( elem ) {
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
}
} else if ( !context && /^\w+$/.test( selector ) ) {
this.selector = selector;
this.context = document;
selector = document.getElementsByTagName( selector );
return jQuery.merge( this, selector );
} else if ( !context || context.jquery ) {
return (context || rootjQuery).find( selector );
} else {
return jQuery( context ).find( selector );
}
// 处理函数参数,直接domReady
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
//处理jQuery对象参数
if (selector.selector !== undefined) {
this.selector = selector.selector;
this.context = selector.context;
}
//无论是数组还是类数组(如NodeList),统统使用jQuery.makeArray来为实例添加新的元素
return jQuery.makeArray( selector, this );
},

另附上makeArray方法与merge方法,merge方法好神奇啊,


代码如下:

makeArray: function( array, results ) {
var ret = results || [];
if ( array != null ) {
// The window, strings (and functions) also have 'length'
// The extra typeof function check is to prevent crashes
// in Safari 2 (See: #3039)
if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) {
push.call( ret, array );
} else {
jQuery.merge( ret, array );
}
}
return ret;
},
merge: function( first, second ) {
var i = first.length, j = 0;
if ( typeof second.length === "number" ) {
for ( var l = second.length; j < l; j++ ) {
first[ i++ ] = second[ j ];
}
} else {
while ( second[j] !== undefined ) {
first[ i++ ] = second[ j++ ];
}
}
first.length = i;
return first;
},

2011-01-23发布的1.5版,其init方法与1.42的变化不大:只有两处做了改动:


代码如下:

//1.42
- ret = buildFragment( [ match[1] ], [ doc ] );
- selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
//1.5
+ ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
+ selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
//1.42
- return jQuery( context ).find( selector );
//1.5
+ return this.constructor( context ).find( selector );//目的就是为了不再生成新实例

2011-05-02发布的jquery1.6,变化不大,只是对HTML片断进行了更严密的判定:


代码如下:

// Are we dealing with HTML string or an ID?
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [ null, selector, null ];
} else {
match = quickExpr.exec( selector );
}

总体来说,jQuery的构造器已经做得非常之完美,基本上达到“改无可改”的地步了。但是要保证其高效运作,我们还需要一点选择器的知识与了解buildFragment方法的运作,因为这两个实在太常用了,但也是最耗性能的。

(0)

相关推荐

  • jquery构造器的实现代码小结

    显然,能做到这一步,其实现是相当的复杂,这个实现就是它的init方法,jQuery的真实构造器.它功能也随着版本的升级而升级,越来越长. 2009-01-13发布的1.3版 复制代码 代码如下: init: function( selector, context ) { // Make sure that a selection was provided selector = selector || document; // 处理节点参数,直接添加属性到新实例上 if ( selector.no

  • PHP ajax+jQuery 实现批量删除功能实例代码小结

    目录结构 piliangshan.php <?php require_once './db_conn.php'; $sql = "select * from user"; $result = mysqli_query($conn, $sql); ?> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>全选演示</tit

  • 这些年、我收集的JQuery代码小结

    1. 如何创建嵌套的过滤器 复制代码 代码如下: //允许你减少集合中的匹配元素的过滤器, //只剩下那些与给定的选择器匹配的部分.在这种情况下, //查询删除了任何没(:not)有(:has) //包含class为"selected"(.selected)的子节点. .filter(":not(:has(.selected))") 2. 如何重用元素搜索 复制代码 代码如下: var allItems = $("div.item"); var

  • jQuery EasyUI Tab 选项卡问题小结

    需要解决的问题: 比如说 我先把行政区域的页面打开之后,我又把产品类型管理的页面打开,之后我再产品类型管理里添加了一条数据,当我点击横着的行政区域选项卡时,我需要使用到产品类型管理岗添加的数据,但是在行政区域里不存在那条数据.我就想让这条数据显示出来,所以我就想当我点击横着的选项卡的时候,我就想让刷新一下页面.这时那条数据就会显示出来. 主要是我完全不知道我点击横着的选项卡触发的事件.代码如下: html 选项卡 <div data-options="region:'center',col

  • jQuery fadeOut 异步实例代码详解

    定义和用法 fadeOut() 方法逐渐改变被选元素的不透明度,从可见到隐藏(褪色效果). 注释:隐藏的元素不会被完全显示(不再影响页面的布局). 提示:该方法通常与 fadeIn() 方法一起使用. 语法 $(selector).fadeOut(speed,easing,callback) 1. 概述 jquery实现动画效果的函数使用起来很方便,不过动画执行是异步的,所以要把自定义的操作放在回调函数里. 2. example <html> <body> <table id

  • jQuery自定义数值抽奖活动代码

    本文实例为大家分享了jquery输入数字随机抽奖特效代码,供大家参考,具体内容如下 代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>jQuery自定义数值抽奖活动代码 - 何问起</title><base target="_blank" /> <script type="text/ja

  • jQuery遍历Form示例代码

    jQuery 遍历 Form,代码如下 复制代码 代码如下: <script type="text/javascript"> // 取得 id 为form1 的 form 的所有输入变量 values = $("#form1").serializeArray(); var values, index; for (index = 0; index < values.length; ++index) { if (values[index].name =

  • jquery css 选择器演示代码

    效果如图所示:核心代码: 复制代码 代码如下: <script type="text/javascript"> $('#one').css("background","#fff"); $('div').css("background","#fff"); $('body div').css("background","#bbffaa");//改变body内所

  • 全面解析DOM操作和jQuery实现选项移动操作代码分享

    DOM: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-"> <title>DOM选项移动操作</title> <style> select { width: px; height: px; } div { display: inline-block; width: px } </style> <

  • jquery实现滑动特效代码

    在项目中,有需求要使用jquery实现滑动效果,于是把相关内容整理如下,下文介绍了很详细,有文字说明和代码分析,需要的朋友可以来学习下. 实现方式一:  .slideUp([duration][,complete])--目标元素向上滑入隐藏: .slideDown([duration][,complete])--目标元素向下滑出显示: .slideToggle([duration][,complete])--目标元素隐藏则向下滑出显示,否则向上滑入隐藏: 注:duration为方法执行的时间区间

随机推荐