Heim > Web-Frontend > js-Tutorial > jquery构造器的实现代码小结_jquery

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

WBOY
Freigeben: 2016-05-16 18:06:41
Original
870 Leute haben es durchsucht

显然,能做到这一步,其实现是相当的复杂,这个实现就是它的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 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.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方法的运作,因为这两个实在太常用了,但也是最耗性能的。
Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage