接上一节的两个函数
selector = jQuery.clean( [ match[1] ], context ); jQuery( context ).find( selector );
clean (约939),find (约)
clean: function( elems, context )
elems : 数组
context : 上下文
var ret = []; ... return ret;
那么ret就相当于是创建好的dom数组
context = context || document;
这种写法经常出现,允许参数缺省
if (typeof context.createElement == 'undefined') context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
这句主要是处理浏览器兼容型问题,因为在ie下context.createElement会打印"object",而不是"function",context.ownerDocument通过字面上意思可以得出是获取document,但出过来的context也可能是window对象,所以就有后面||的故事了。对于为什么不直接写document,我的理解是他可能是想对xml也添加支持,所以在大师脚下一定不要有自以为是这种想法,这是很危险的,我们除了敬仰就剩下仰望了,保持一颗虔诚的心,来看下面的代码。
下面是一段jQuery.each(elems, function(i, elem),然后就直接return ret了
先来看看jQuery.each代码
each: function( object, callback, args ) {
var name, i = 0, length = object.length;
if ( args ) {
if ( length == undefined ) {
....//1
break;
} else
....//2
break;
} else {
if ( length == undefined ) {
....//3
break;
} else
...//4
}
return object;
}args是用来供内部使用的,我来从1,2,3,4一个一个分析
//1 存在args,但是没有length属性object
for ( name in object ) if ( callback.apply( object[ name ], args ) === false ) break;
遍历object里面的属性然后执行callback方法,而且将args注入进来,当返回值为false的情况下终止循环,注意是用的"===",返回0,"false"是无效的
//2 和 //1一样,只是他是一个含有length的object,便利的方式不同而已,毕竟for要比foreach速度上要快
//3 外部使用,无length属性
for ( name in object ) if ( callback.call( object[ name ], name, object[ name ] ) === false ) break;这个就看的很清楚了,当我们使用
$.each(["aa","bb"],function(i,n){ alert(n == this)}) //true就可以知道其原因了//4
for ( var value = object[0];i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
看似好像和前面不一样,其实这只是一种幻觉,他只是把工作全部转移到for里面去了,充分的利用了语法,可读性下去了,性能没测不好评论,不过这种花式写法我还是推崇的,毕竟写代码是个枯燥无味的,有时候能利用智慧玩点花样找点乐子,也是一种生活态度
言归正传,继续clean
jQuery.each(elems, function(i, elem){
if ( !elem ) return; //elem为null继续下一个循环
if ( elem.constructor == Number ) elem += ''; //将数字变为字符串
....
//form和select都有length
if ( elem.length === 0 && (!jQuery.nodeName( elem, "form" ) && !jQuery.nodeName( elem, "select" )) )
return; //并且不是form和select,继续下一个循环
if ( elem[0] == undefined || jQuery.nodeName( elem, "form" ) || elem.options )//假设它不是一个类数组了或者它是一个form或select
ret.push( elem );
else
//它就是一个数组
ret = jQuery.merge( ret, elem );
}
nodeName: function( elem, name ) {
return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
}
//向first上追加second
merge: function( first, second ) {
var i = 0, elem, pos = first.length;
if ( jQuery.browser.msie ) {
while ( elem = second[ i++ ] )
if ( elem.nodeType != 8 )
first[ pos++ ] = elem;
} else
while ( elem = second[ i++ ] )
first[ pos++ ] = elem;
return first;
}
现在来分析上面那个...段的代码
elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag) {
return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
all :
front + "></" + tag + ">";
}); 试验这样一段代码 : $("<input type=\"text\" value=\"haha\" />")
下面使用alert打印的结果
all: <input type="text" value="哈哈"/>
front: <input type="text" value="哈哈"
tag: input
其实本意目的就是将<div/> 改为<div></div>
//去空白创建,临时div
var tags = jQuery.trim(elem).toLowerCase(), div = context.createElement("div");
var wrap =
!tags.indexOf("<opt") &&
[1, "<select multiple='multiple'>", "</select>"] ||
!tags.indexOf("<leg") &&
[1, "<fieldset>", "</fieldset>"] ||
tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
[1, "<table>", "</table>"] ||
!tags.indexOf("<tr") &&
[2, "<table><tbody>", "</tbody></table>"] ||
(!tags.indexOf("<td") || !tags.indexOf("<th")) &&
[3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
!tags.indexOf("<col") &&
[2, "<table><tbody></tbody><colgroup>", "</colgroup></table>"] ||
jQuery.browser.msie &&
[1, "div<div>", "</div>"] ||
[0, "", ""]; 建立了一个数组,这个数组时干嘛的呢.就比如说opt必须是放在select地下,而leg必须放在fieldset底下,前面的数字代表深度
div.innerHTML = wrap[1] + elem + wrap[2]; //不解释
//通过深度得到最内层的元素,如"<table><tbody><tr>", "</tr></tbody></table>"得到的就是里面的最里面td
while (wrap[0]--)
div = div.lastChild;
if (jQuery.browser.msie) {
var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
div.firstChild && div.firstChild.childNodes :
wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
div.childNodes :
[];
for (var j = tbody.length - 1; j >= 0; --j)
if (jQuery.nodeName(tbody[j], "tbody") && !tbody[j].childNodes.length)
tbody[j].parentNode.removeChild(tbody[j]);
//ie当使用innerHTML的时候会自动去掉空白节点,下面就是将其恢复
if (/^\s/.test(elem))
div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]), div.firstChild);
} 可见深度主要是针对ie兼容性的问题,ie又一次的擅住主张,自动加入tbody,jquery作者真是煞费苦心啊