jQuery1.3代码深度分析(clean)
// 把html转换成Dom元素,elems多个html string 的数组1.2.6得时候只有两个参数,新的版本中加了fragment第三个参数
context = context || document;
//默认的上下文是document
//在IE中!context.createElement行不通,因为它返回对象类型
// !context.createElement fails in IE with an error but returns typeof 'object'
if ( typeof context.createElement === "undefined" )
//这里支持context为jQuery对象,取第一个元素。
context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
// If a single string is passed in and it's a single tag
// just do a createElement and skip the rest
//这是1.3新加的,如果是单独得标签比如:$('<div />') 直接调用createElement
if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
var match = /^<(\w+)\s*\/?>$/.exec(elems[0]);
if ( match )
return [ context.createElement( match[1] ) ];
}
var ret = [], scripts = [], div = context.createElement("div");
jQuery.each(elems, function(i, elem){
if ( typeof elem === "number" )
elem += '';
// 把int 转换成string的最高效的方法
if ( !elem )
return;
// Convert html string into DOM nodes // 转换html为Dom元素
if ( typeof elem === "string" ) {
// Fix "XHTML"-style tags in all browsers
// 修正 "XHTML"-style 标签,对于如<div/>的形式修改为<div></div>
//但是对于(abbr|br|col|img|input|link|meta|param|hr|area|embed)不修改
//front=(<(\w+)[^>]*?)
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 + ">";
});
// Trim whitespace, otherwise indexOf won't work as expected
// 去空格,否则indexof不能正常工作
var tags = jQuery.trim( elem ).toLowerCase();
// 有些标签必须是有一些约束的,比如<option>必须在<select></select>中间
// 下面的代码在大部分是对<table>中子元素进行修正。数组中第一个元素为深度
//&&>||
var wrap =
// option or optgroup
!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>" ] ||
// <thead> matched above
(!tags.indexOf("<td") || !tags.indexOf("<th")) &&
[ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
!tags.indexOf("<col") &&
[ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
// IE can't serialize <link> and <script> tags normally
!jQuery.support.htmlSerialize &&
[ 1, "div<div>", "</div>" ] ||
[ 0, "", "" ];
// Go to html and back, then peel off extra wrappers
// 包裹html之后,采用innerHTML转换成Dom
div.innerHTML = wrap[1] + elem + wrap[2];
// Move to the right depth
while ( wrap[0]-- )
div = div.lastChild;
// Remove IE's autoinserted <tbody> from table fragments
if ( !jQuery.support.tbody ) {
// String was a <table>, *may* have spurious <tbody>
var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
div.firstChild && div.firstChild.childNodes :
// String was a bare <thead> or <tfoot>
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 completely kills leading whitespace when innerHTML is used
if ( !jQuery.support.leadingWhitespace && /^\s/.test( elem ) )
div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
elem = jQuery.makeArray( div.childNodes );
}
if ( elem.nodeType )
ret.push( elem );
else
ret = jQuery.merge( ret, elem );
});
//这段是新加的处理js代码,同时也取消了form的处理
if ( fragment ) {
for ( var i = 0; ret[i]; i++ ) {
if ( jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
} else {
if ( ret[i].nodeType === 1 )
ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
fragment.appendChild( ret[i] );
}
}
return scripts;
}
return ret;
},
},
这 个方法主要解决html到dom的转换,在1.3选择器中接着比较重要就是xpath的选择了。以前得版本是自己写的,新得版本是整合了Sizzle,类 似jQuery.find=Sizzle.find,这样代码重载jQuery得选择器,下节再讲Sizzle,实际上选择得原理和1.2.6是一样的, 只是有点细节上的区别。
莫愁前路无知己,天下无人不识君。