您好,欢迎访问一九零五行业门户网

jquery构造器的实现代码小结_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 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方法的运作,因为这两个实在太常用了,但也是最耗性能的。
其它类似信息

推荐信息