接上一节的两个函数
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作者真是煞费苦心啊