jquery 1.7.2源码解析(二)构造jquery对象
構(gòu)造jquery對象
jQuery對象是一個類數(shù)組對象。
一)構(gòu)造函數(shù)jQuery()
構(gòu)造函數(shù)的7種用法:
?
1.jQuery(selector [, context ])
傳入字符串參數(shù):檢查該字符串是選擇器表達(dá)式還是HTML代碼。如果是選擇器表達(dá)式,則遍歷文檔查找匹配的DOM元素,
并創(chuàng)建一個包含這些DOM元素引用的jQuery對象。如果沒有匹配的DOM,則創(chuàng)建一個length屬性為0的空jQuery對象。
默認(rèn)情況下對匹配元素的查找從根元素document開始,但也可以傳入context參數(shù)限制查找范圍。
如果選擇器表達(dá)式是簡單的'#id'且沒有context參數(shù),則調(diào)用document.getElementById()查找。
如果不是則調(diào)用jQuery的find()方法。
2.jQuery(html [, ownerDocument])、jQuery(html, props)
如果傳入的參數(shù)是html代碼,則嘗試用html代碼創(chuàng)建新的DOM元素,并創(chuàng)建包含這些DOM元素引用的jQuery對象。
如果html代碼是單獨的標(biāo)簽,使用document.createElement()創(chuàng)建DOM元素。如果是復(fù)雜的html代碼,則使用innerHTML.
參數(shù)ownerDocument用于創(chuàng)建新DOM元素的文檔對象,如果不傳入默認(rèn)為當(dāng)前文檔對象。
如果html代碼是單獨標(biāo)簽,第二個參數(shù)還可以是props,props是一個包含了屬性、事件的普通對象,在調(diào)用了document.createElement()
方法創(chuàng)建了DOM元素后,參數(shù)props會被傳給jQuery的attr()方法,由該方法設(shè)置新DOM的屬性,事件。
$('<div/>', {"class": "test",text: "Click me!",click: function () {console.log("log");}
}); 3.jQuery(element)、jQuery(elementArray)
如果傳入一個DOM元素或者DOM元素數(shù)組,則封裝DOM元素到j(luò)Query對象種,并返回該jQuery對象。
$('#aInput').click(function () {$(this).val("value");
}); 4.jQuery(object)
傳入一個普通的js對象,則把該對象封裝到j(luò)Query對象中,并返回jQuery對象。
這個功能可以方便地在普通js對象上實現(xiàn)自定事件的綁定和觸發(fā)。
var person = {name: 'Tony', gender: 'man'}; var $person = $(person); $person.on('custom', function () {//do sth });
5.jQuery(callback)
如果傳入一個函數(shù),則在document上綁定一個ready事件監(jiān)聽函數(shù),當(dāng)DOM結(jié)構(gòu)加載完成時執(zhí)行。
注意:ready事件要早于load事件發(fā)生。
6.jQuery(jQuery object)
創(chuàng)建一個副本并返回。
二)總體結(jié)構(gòu)
jQuery對象模塊總體結(jié)構(gòu):
(function ( window, undefined ) {//構(gòu)造jQuery對象var jQuery = (function () {var jQuery = function (selector,context) {return new jQuery.fn.init(selector, context, rootjQuery);},//一堆局部變量聲明//jQuery.fn成為jQuery.prototype的簡寫//覆蓋jQuery原型的目的:方便繼承,順便也減少了創(chuàng)建每個jQuery實例所消耗的內(nèi)存jQuery.fn = jQuery.prototype = {constructor: jQuery,init: function (selector, context, rootjQuery) {},//一堆原型屬性和方法 };//用jQuery的原型對象覆蓋jQuery.fn.init.prototype的原型對象//使 new jQuery.fn.init()返回的實例也可以構(gòu)造函數(shù)jQuery()的原型方法和屬性
jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend = jQuery.fn.extend = function () {};jQuery.extend({//一堆靜態(tài)屬性和方法 });return jQuery;})();//省略其他模塊代碼window.jQuery = window.$ = jQuery; })(window);
三)jQuery.fn.init(selector, context, rootjQuery)
1.12個分支
?
?2.源碼分析
?1)定義jQuery.fn.init(selector, context, rootjQuery):
jQuery.fn = jQuery.prototype = {constructor: jQuery,init: function( selector, context, rootjQuery ) {var match, elem, ret, doc;
該構(gòu)造函數(shù)接收三個參數(shù):
selector:
context: 不傳入,或者傳入DOM元素,jQuery對象,普通js對象之一。
rootjQuery: 包含了document對象的jQuery對象。用于:
1.document.getElementById()查找失敗
2.selector是選擇器表達(dá)式且未指定context
3.selector是函數(shù)
2)參數(shù)selector可以轉(zhuǎn)換為false
// Handle $(""), $(null), or $(undefined)if ( !selector ) {return this;}
3)參數(shù)selector是DOM元素
?
// Handle $(DOMElement)if ( selector.nodeType ) {this.context = this[0] = selector;this.length = 1;return this;}
?
4)參數(shù)selector是字符串'body'
// The body element only exists once, optimize finding itif ( selector === "body" && !context && document.body ) {this.context = document;this[0] = document.body;this.selector = selector;this.length = 1;return this;}
5)參數(shù)selector是其他字符串
先檢測selector是HTML代碼還是#id
// Handle HTML stringsif ( typeof selector === "string" ) {// Are we dealing with HTML string or an ID?if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {// Assume that strings that start and end with <> are HTML and skip the regex checkmatch = [ null, selector, null ];} else {match = quickExpr.exec( selector );}
?
1.參數(shù)selector是單獨標(biāo)簽
則調(diào)用document.createElement()創(chuàng)建DOM元素:
//如果是字符串if (typeof selector === 'string') {//如果是HTML字符串if (selector.charAt(0) === '<' && selector.charAt(length-1) === '>' && selector.length >= 3) {match = [null, selector, null];} else {match = quickExpr.exec(selector);}}if (match && (match[1] || !context)) {//HANDLE: $(html) -> $(array)if (match[1]) {context = context instanceof jQuery ? context[0] : context;doc = (context ? context.ownerDocument || context : document);//如果只傳入了一個字符串,并且是個簡單的html標(biāo)簽//就調(diào)用createElement,跳過剩余部分。ret = rsingleTag.exec( selector );if (ret) {//是否是純粹對象if ( jQuery.isPlainObject( context ) ) {selector = [document.createElement(ret[1])];jQuery.fn.attr.call( selector, context, true );} else {selector = [document.createElement(ret[1])];}} else {ret = jQuery.buildFragment( match[1], [doc] );}
2.參數(shù)selector是復(fù)雜HTML代碼
} else {ret = jQuery.buildFragment( [ match[1] ], [ doc ] );selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;}//將創(chuàng)建的DOM元素合并到當(dāng)前jQuery對象中,并返回return jQuery.merge( this, selector );
?3.參數(shù)selector是"#id",且未指定參數(shù)context
// HANDLE: $("#id")} else {elem = document.getElementById( match[2] );// Check parentNode to catch when Blackberry 4.6 returns// nodes that are no longer in the document #6963if ( elem && elem.parentNode ) {// Handle the case where IE and Opera return items// by name instead of IDif ( elem.id !== match[2] ) {return rootjQuery.find( selector );}// Otherwise, we inject the element directly into the jQuery objectthis.length = 1;this[0] = elem;}this.context = document;this.selector = selector;return this;}
4.參數(shù)selector是選擇器表達(dá)式
// HANDLE: $(expr, $(...))} else if ( !context || context.jquery ) {return ( context || rootjQuery ).find( selector );// HANDLE: $(expr, context)// (which is just equivalent to: $(context).find(expr)} else {return this.constructor( context ).find( selector );}
5.參數(shù)selector是函數(shù)
// HANDLE: $(function)// Shortcut for document ready} else if ( jQuery.isFunction( selector ) ) {return rootjQuery.ready( selector );}
6.參數(shù)selector是jQuery對象
if ( selector.selector !== undefined ) {this.selector = selector.selector;this.context = selector.context;}
7.參數(shù)selector是其他任意值
如果selector是數(shù)組或者偽數(shù)組,則都添加到j(luò)Query對象中,如果是JS
對象則作為第一個元素放入。該方法也可將6)中selector包含的全部元素引用復(fù)制到當(dāng)前jQuery
?
return jQuery.makeArray( selector, this );
?
四)jQuery.buildFragment(args, nodes, scripts)
1.實現(xiàn)原理
該方法會先創(chuàng)建一個文檔片段DocumentFragment,然后調(diào)用方法jQuery.clean(elems, context, fragment, scripts)
將HTML代碼轉(zhuǎn)換為HTML元素,并存儲在創(chuàng)建的DocumentFragment中。
此外,如果HTML代碼符合緩存條件,該方法還會把轉(zhuǎn)換后的DOM緩存起來,第三次轉(zhuǎn)換相同的HTML代碼時直接從緩存中讀取。
2.源碼分析
1)參數(shù):
args:數(shù)組,含有待轉(zhuǎn)換為DOM元素的html代碼
nodes:數(shù)組,含有文檔對象、jQuery對象或DOM元素,用于修正創(chuàng)建文檔片段DocumentFragment的文檔對象。
scripts:數(shù)組,用于存放HTML代碼中的script元素。
2)定義局部變量,修正文檔對象doc
?
* * fragment:指向創(chuàng)建的DocumentFragment * cacheable: 是否符合緩存條件 * cacheresult:指向從緩存對象,jQuery.fragments提取到的文檔片段,其中包含了緩存的DOM元素 * doc:創(chuàng)建文檔片段的文檔對象 * */ var fragment, cacheable, cacheresults, doc,first = args[ 0 ];// nodes may contain either an explicit document object, // a jQuery collection or context object. // If nodes[0] contains a valid object to assign to doc if ( nodes && nodes[0] ) {doc = nodes[0].ownerDocument || nodes[0]; }// Ensure that an attr object doesn't incorrectly stand in as a document object // Chrome and Firefox seem to allow this to occur and will throw exception // Fixes #8950 if ( !doc.createDocumentFragment ) {doc = document; }
?
3)其他操作
// Only cache "small" (1/2 KB) HTML strings that are associated with the main document // Cloning options loses the selected state, so don't cache them // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501 if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&first.charAt(0) === "<" && !rnocache.test( first ) &&(jQuery.support.checkClone || !rchecked.test( first )) &&(jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {cacheable = true;cacheresults = jQuery.fragments[ first ];if ( cacheresults && cacheresults !== 1 ) {fragment = cacheresults;} } //轉(zhuǎn)換HTML代碼為DOM元素 if ( !fragment ) {fragment = doc.createDocumentFragment();jQuery.clean( args, doc, fragment, scripts ); } //把轉(zhuǎn)換后的DOM元素放入緩存對象jQuery.fragments中 if ( cacheable ) {jQuery.fragments[ first ] = cacheresults ? fragment : 1; } //返回文檔片段和返回狀態(tài) return { fragment: fragment, cacheable: cacheable }; };jQuery.fragments = {};
五)jQuery.clean(elems, context, fragment, scripts)
1.實現(xiàn)原理
該方法負(fù)責(zé)把HTML代碼轉(zhuǎn)換為DOM元素,并提取其中的script元素。該方法會先創(chuàng)建一個臨時
的div元素,并將其插入一個安全的文檔片段(能正確渲染HTML5元素的文檔片段)中,
然后把HTML代碼賦值給div元素的innerHTML屬性,最后解析div元素的子元素得到轉(zhuǎn)換后的DOM。
2.源碼分析
1)參數(shù):
elems:數(shù)組,包含了待轉(zhuǎn)換的html代碼
context:文檔對象
fragment:文檔片段,存放轉(zhuǎn)換后的DOM元素
scripts:數(shù)組,存放轉(zhuǎn)換后的DOM元素中的script元素
2)修正文檔對象
//ret用于存放轉(zhuǎn)換后的DOM元素
var checkScriptType, script, j,ret = [];context = context || document;// !context.createElement fails in IE with an error but returns typeof 'object' if ( typeof context.createElement === "undefined" ) {context = context.ownerDocument || context[0] && context[0].ownerDocument || document; }
3)遍歷elems數(shù)組
//這里使用"!=",可以同時過濾undefined,null的情況,但不會過濾掉0 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {//如果elem是數(shù)字,則轉(zhuǎn)換為字符串類型if (typeof elem === "number") {elem += "";}//如果elem是0,此時已經(jīng)被轉(zhuǎn)換為字符串“0”if (!elem) {continue;}
1.創(chuàng)建文本節(jié)點:
如果字符串不包含標(biāo)簽、字符代碼和數(shù)字代碼,則調(diào)用原生方法document.createTextNode()方法創(chuàng)建文本節(jié)點。
if ( !rhtml.test( elem ) ) {elem = context.createTextNode( elem );} else {
rhtml = /<|&#?\w+;/,
為什么不能包含標(biāo)簽、字符代碼和數(shù)字代碼?
因為document.createTextNode()方法對于傳給它的字符串不會做轉(zhuǎn)義解析。
而瀏覽器innerHTML機(jī)制可以。
2.修正自關(guān)閉標(biāo)簽
else {// Fix "XHTML"-style tags in all browserselem = elem.replace(rxhtmlTag, "<$1></$2>");
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
3.創(chuàng)建一個臨時的div
// Trim whitespace, otherwise indexOf won't work as expectedvar tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
//從wrapMap提取對應(yīng)的父標(biāo)簽,因為HTML語法要求這些標(biāo)簽必須包含在父標(biāo)簽中wrap = wrapMap[ tag ] || wrapMap._default,
//包裹的深度,稍后會根據(jù)該變量剝?nèi)ジ冈豥epth = wrap[0],div = context.createElement("div"),
rtagName = /<([\w:]+)/,
wrapMap = {option: [ 1, "<select multiple='multiple'>", "</select>" ],legend: [ 1, "<fieldset>", "</fieldset>" ],thead: [ 1, "<table>", "</table>" ],tr: [ 2, "<table><tbody>", "</tbody></table>" ],td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],area: [ 1, "<map>", "</map>" ],_default: [ 0, "", "" ]},
4.把臨時div插入安全文檔中去
// Append wrapper element to unknown element safe doc fragmentif ( context === document ) {// Use the fragment we've already created for this document safeFragment.appendChild( div );} else {// Use a fragment created with the owner document createSafeFragment( context ).appendChild( div );}
safeFragment = createSafeFragment( document );
function createSafeFragment( document ) {var list = nodeNames.split( "|" ),safeFrag = document.createDocumentFragment();if ( safeFrag.createElement ) {while ( list.length ) {safeFrag.createElement(list.pop());}}return safeFrag; }
5.轉(zhuǎn)換html代碼為DOM元素
// Go to html and back, then peel off extra wrappers div.innerHTML = wrap[1] + elem + wrap[2];// Move to the right depth while ( depth-- ) {div = div.lastChild; }
6.移除IE6\7自動插入的空tbody元素
// Remove IE's autoinserted <tbody> from table fragmentsif ( !jQuery.support.tbody ) {// String was a <table>, *may* have spurious <tbody>var hasBody = rtbody.test(elem),tbody = tag === "table" && !hasBody ?div.firstChild && div.firstChild.childNodes :// String was a bare <thead> or <tfoot>wrap[1] === "<table>" && !hasBody ?div.childNodes :[];for ( j = tbody.length - 1; j >= 0 ; --j ) {if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {tbody[ j ].parentNode.removeChild( tbody[ j ] );}}}
7)插入IE6\7\8自動刪除的前導(dǎo)空白
// IE completely kills leading whitespace when innerHTML is usedif ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );}
8)取到轉(zhuǎn)換后的DOM元素集合
elem = div.childNodes;
9)修正IE7、8中復(fù)選框和單選框選中問題
略
10)合并轉(zhuǎn)換后的DOM元素
if ( elem.nodeType ) {ret.push( elem );} else {ret = jQuery.merge( ret, elem );}
4)傳入了fragment的情況
?
if ( fragment ) {checkScriptType = function( elem ) {return !elem.type || rscriptType.test( elem.type );};for ( i = 0; ret[i]; i++ ) {script = ret[i];if ( scripts && jQuery.nodeName( script, "script" ) && (!script.type || rscriptType.test( script.type )) ) {scripts.push( script.parentNode ? script.parentNode.removeChild( script ) : script );} else {if ( script.nodeType === 1 ) {var jsTags = jQuery.grep( script.getElementsByTagName( "script" ), checkScriptType );ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );}fragment.appendChild( script );}}}return ret;
?六)jQuery.extend()、jQuery.fn.extend()
1.如何使用
用于合并兩個或者多個對象的屬性到第一個對象,語法:
jQuery.extend([deep], target, object1[, objectN]);
jQuery.fn.extend([deep], target, object1[, objectN]);
deep:布爾值,是否進(jìn)行遞歸合并,默認(rèn)為不遞歸
target:目標(biāo)對象
objectN:源對象,包含的待合并的屬性
如果僅提供一個對象,參數(shù)target將被忽略,當(dāng)前的jQuery或者jQuery.fn被當(dāng)作目標(biāo)對象
通過這種方式在jQuery或者jQuery.fn上添加新的屬性或者方法。
2.源碼分析
1)定義局部變量
jQuery.extend = jQuery.fn.extend = function() {var options, name, src, copy, copyIsArray, clone,target = arguments[0] || {},i = 1,length = arguments.length,deep = false;
options:指向某個源對象
name:指向某個源對象的某個屬性名
src:某個目標(biāo)對象的某個屬性原始值
copy:某個源對象的某個屬性值
copyIsArray:指示變量copy是否是數(shù)組
clone:深度復(fù)制時,原始值的修正值
target:指向目標(biāo)對象
i:源對象的起始下標(biāo)
length:表示參數(shù)的個數(shù),用于修正變量target
deep:是否深度合并,默認(rèn)為false
jQuery.extend = jQuery.fn.extend = function() {var options, name, src, copy, copyIsArray, clone,target = arguments[0] || {},i = 1,length = arguments.length,deep = false;// Handle a deep copy situationif ( typeof target === "boolean" ) {deep = target;target = arguments[1] || {};// skip the boolean and the targeti = 2;}// Handle case when target is a string or something (possible in deep copy)if ( typeof target !== "object" && !jQuery.isFunction(target) ) {target = {};}// extend jQuery itself if only one argument is passedif ( length === i ) {target = this;--i;}for ( ; i < length; i++ ) {// Only deal with non-null/undefined valuesif ( (options = arguments[ i ]) != null ) {// Extend the base objectfor ( name in options ) {src = target[ name ];copy = options[ name ];// Prevent never-ending loopif ( target === copy ) {continue;}// Recurse if we're merging plain objects or arraysif ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {if ( copyIsArray ) {copyIsArray = false;clone = src && jQuery.isArray(src) ? src : [];} else {clone = src && jQuery.isPlainObject(src) ? src : {};}// Never move original objects, clone themtarget[ name ] = jQuery.extend( deep, clone, copy );// Don't bring in undefined values} else if ( copy !== undefined ) {target[ name ] = copy;}}}}// Return the modified objectreturn target; };
七)原型屬性和方法
1. .selector、.jQuery、.length、.size()
1)selector:用于記錄jQuery查找和過濾DOM元素時的選擇器表達(dá)式,可用于調(diào)試。
2)jQuery:表示jQuery的版本號
3)length:表示當(dāng)前jQuery對象中元素的個數(shù)
4)方法size():功能上等價于length
// Start with an empty selectorselector: "",// The current version of jQuery being usedjquery: "1.7.2",// The default length of a jQuery object is 0length: 0,// The number of elements contained in the matched element setsize: function() {return this.length;},
2..toArray()、.get([index])
1.toArray():將當(dāng)前jQuery對象轉(zhuǎn)換為真正的數(shù)組,轉(zhuǎn)換后的數(shù)組包含了所有元素。
slice = Array.prototype.slice,
toArray: function() {return slice.call( this, 0 );},
2.get([index]):返回當(dāng)前jQuery對象中指定位置的元素或包含了全部元素的數(shù)組(無參)。
get: function( num ) {return num == null ?// Return a 'clean' arraythis.toArray() :// Return just the object( num < 0 ? this[ this.length + num ] : this[ num ] );},
3. .each( function(index, Elment) )、 jQuery.each( collection, callback( indexArray, valueOfValue ) )
1. .each( function(index, Elment) )
遍歷當(dāng)前jQuery對象,并在每個元素上執(zhí)行回調(diào)函數(shù)。每當(dāng)執(zhí)行回調(diào)函數(shù)
?函數(shù)執(zhí)行時會傳遞當(dāng)前循環(huán)次數(shù)作為參數(shù),更重要的是回調(diào)函數(shù)在當(dāng)前
上下文環(huán)境中觸發(fā),在回調(diào)函數(shù)中返回false可以終止遍歷。
each: function( callback, args ) {return jQuery.each( this, callback, args );},
2.jQuery.each( collection, callback ( indexArray, valueOfValue ) )
通用的遍歷方法,用于無縫地遍歷對象和數(shù)組,對于數(shù)組和類數(shù)組通過下標(biāo)
遍歷,對于其他對象則通過屬性名遍歷。在遍歷過程中如果回調(diào)函數(shù)返回false則結(jié)束遍歷。
?
/* ** object:待遍歷的對象或者數(shù)組* callback: 回調(diào)函數(shù),會在數(shù)組的每個元素或者對象的每個屬性上執(zhí)行* args: 傳遞給回調(diào)函數(shù)的參數(shù)數(shù)組,可選,如果沒有傳入,則執(zhí)行回調(diào)* 函數(shù)時傳入兩個參數(shù)(下標(biāo)或?qū)傩悦?#xff0c;元素或?qū)傩灾?#xff09;,如果傳入了參數(shù)* 則把該參數(shù)傳遞給回調(diào)函數(shù)。** */ each: function( object, callback, args ) {var name, i = 0,length = object.length,isObj = length === undefined || jQuery.isFunction( object );if ( args ) {if ( isObj ) {for ( name in object ) {if ( callback.apply( object[ name ], args ) === false ) {break;}}} else {for ( ; i < length; ) {if ( callback.apply( object[ i++ ], args ) === false ) {break;}}}// A special, fast, case for the most common use of each} else {if ( isObj ) {for ( name in object ) {if ( callback.call( object[ name ], name, object[ name ] ) === false ) {break;}}} else {for ( ; i < length; ) {if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {break;}}}}return object; },
?
4. .map( callback(index, domElement) )、 jQuery.map( arrayOrObject, callback(value, indexOrKey) )
1) .map( callback(index, domElement) )
遍歷當(dāng)前jQuery對象,在每個元素上執(zhí)行回調(diào)函數(shù),并將回調(diào)函數(shù)的返回值放入一個新的jQuery對象中。
map: function( callback ) {return this.pushStack( jQuery.map(this, function( elem, i ) {return callback.call( elem, i, elem );}));},
2)?jQuery.map( arrayOrObject, callback(value, indexOrKey) )
對數(shù)組的每個元素或者對象的每個屬性調(diào)用一個回調(diào)函數(shù),并將回調(diào)函數(shù)的返回值放入一個新的數(shù)組中。
執(zhí)行回調(diào)函數(shù)時傳入兩個參數(shù):數(shù)組元素或?qū)傩灾?#xff0c;元素下標(biāo)或?qū)傩悦jP(guān)鍵字this指向全局對象window。
//參數(shù)arg僅限于jQuery內(nèi)部使用 map: function( elems, callback, arg ) {var value, key, ret = [],i = 0,length = elems.length,// jquery objects are treated as arraysisArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;// Go through the array, translating each of the items to theirif ( isArray ) {for ( ; i < length; i++ ) {value = callback( elems[ i ], i, arg );if ( value != null ) {ret[ ret.length ] = value;}}// Go through every key on the object,} else {for ( key in elems ) {value = callback( elems[ key ], key, arg );if ( value != null ) {ret[ ret.length ] = value;}}}// Flatten any nested arraysreturn ret.concat.apply( [], ret ); },
5. .pushStack( elements, name, arguments )
創(chuàng)建一個新的空jQuery對象,然后把DOM對象元素集合放入對象中,并保留對當(dāng)前jQuery對象的引用。
//elems: 放入新jQuery對象的元素數(shù)組 //name: 產(chǎn)生元素數(shù)組的jQuery方法名 //修正原型屬性的.selector pushStack: function( elems, name, selector ) {// Build a new jQuery matched element setvar ret = this.constructor();if ( jQuery.isArray( elems ) ) {push.apply( ret, elems );} else {jQuery.merge( ret, elems );}// Add the old object onto the stack (as a reference)ret.prevObject = this;ret.context = this.context;if ( name === "find" ) {ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;} else if ( name ) {ret.selector = this.selector + "." + name + "(" + selector + ")";}// Return the newly-formed element setreturn ret; },
6. ?.end()
?
end: function() {return this.prevObject || this.constructor(null);},
?
7. .eq(index)、 .first()、 .last()、 .slice(start[, end])
eq: function( i ) {i = +i;return i === -1 ?this.slice( i ) :this.slice( i, i + 1 );},first: function() {return this.eq( 0 );},last: function() {return this.eq( -1 );},slice: function() {return this.pushStack( slice.apply( this, arguments ),"slice", slice.call(arguments).join(",") );},
八)靜態(tài)屬性和方法
1. jQuery.onConflit([removeAll])
用于釋放jQuery對全局變量的控制權(quán)
// Map over jQuery in case of overwrite_jQuery = window.jQuery,// Map over the $ in case of overwrite_$ = window.$,
?
noConflict: function( deep ) {if ( window.$ === jQuery ) {window.$ = _$;}if ( deep && window.jQuery === jQuery ) {window.jQuery = _jQuery;}return jQuery;},
2.類型檢測:jQuery.isFunction(obj)、 jQuery.isArray(obj)、jQuery.isWindow(obj)、
jQuery.isNumeric(value)、jQuery.type(obj)、jQuery.isPlainObject(object)、jQuery.isEmptyObject(object)
?
isFunction: function( obj ) {return jQuery.type(obj) === "function"; },isArray: Array.isArray || function( obj ) {return jQuery.type(obj) === "array"; },isWindow: function( obj ) {return obj != null && obj == obj.window; },isNumeric: function( obj ) {return !isNaN( parseFloat(obj) ) && isFinite( obj ); },type: function( obj ) {return obj == null ?String( obj ) :class2type[ toString.call(obj) ] || "object"; },//是否是以{}或者new Object()創(chuàng)建的 isPlainObject: function( obj ) {// Must be an Object.// Because of IE, we also have to check the presence of the constructor property.// Make sure that DOM nodes and window objects don't pass through, as wellif ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {return false;}try {// Not own constructor property must be Object//如果obj沒有屬性constructor,則說明該對象必然是通過對象字面量{}創(chuàng)建if ( obj.constructor &&!hasOwn.call(obj, "constructor") &&!hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {return false;}} catch ( e ) {// IE8,9 Will throw exceptions on certain host objects #9897return false;}// Own properties are enumerated firstly, so to speed up,// if last one is own, then all properties are own.//在for循環(huán)中會先枚舉非繼承屬性,再枚舉繼承屬性var key;for ( key in obj ) {}return key === undefined || hasOwn.call( obj, key ); },isEmptyObject: function( obj ) {for ( var name in obj ) {return false;}return true; },
?
3.解析JSON和XML:jQuery.parseJSON(data)、 jQuery.parseXML(data)
1.jQuery.parseJSON(data)
parseJSON: function( data ) {if ( typeof data !== "string" || !data ) {return null;}// Make sure leading/trailing whitespace is removed (IE can't handle it)data = jQuery.trim( data );// Attempt to parse using the native JSON parser firstif ( window.JSON && window.JSON.parse ) {return window.JSON.parse( data );}// Make sure the incoming data is actual JSON// Logic borrowed from http://json.org/json2.jsif ( rvalidchars.test( data.replace( rvalidescape, "@" ).replace( rvalidtokens, "]" ).replace( rvalidbraces, "")) ) {return ( new Function( "return " + data ) )();}jQuery.error( "Invalid JSON: " + data );},
2.jQuery.parseXML(data)
parseXML: function( data ) {if ( typeof data !== "string" || !data ) {return null;}var xml, tmp;try {if ( window.DOMParser ) { // Standardtmp = new DOMParser();xml = tmp.parseFromString( data , "text/xml" );} else { // IExml = new ActiveXObject( "Microsoft.XMLDOM" );xml.async = "false";xml.loadXML( data );}} catch( e ) {xml = undefined;}if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {jQuery.error( "Invalid XML: " + data );}return xml;},
4.jQuery.globalEval( code )
用于在全局作用域中執(zhí)行javascript代碼
?
globalEval: function( data ) {if ( data && rnotwhite.test( data ) ) {// We use execScript on Internet Explorer// We use an anonymous function so that context is window// rather than jQuery in Firefox( window.execScript || function( data ) {window[ "eval" ].call( window, data );} )( data );}},
?
5.jQuery.camelCase(string)
轉(zhuǎn)換連字符形式的字符串為駝峰式
略
6.jQuery.nodeName(elem, name)
用于檢查節(jié)點名稱是否與指定值相等,檢查時忽略大小寫
nodeName: function( elem, name ) {return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();},
?7. 數(shù)組操作方法
1.jQuery.makeArray(obj)
將類數(shù)組對象轉(zhuǎn)換為真正的數(shù)組
// results is for internal usage onlymakeArray: function( array, results ) {var ret = results || [];if ( array != null ) {// The window, strings (and functions) also have 'length'// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930var type = jQuery.type( array );if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {push.call( ret, array );} else {jQuery.merge( ret, array );}}return ret;},
2. jQuery.inArray(value, array[, fromIndex])
在數(shù)組中查找指定的元素并返回其下標(biāo),未找到則返回-1
/* * elem: 要查找的值 * array: 被遍歷的數(shù)組 * i: 指定開始查找的位置 * */ inArray: function( elem, array, i ) {var len;if ( array ) {if ( indexOf ) {return indexOf.call( array, elem, i );}len = array.length;i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;for ( ; i < len; i++ ) {// Skip accessing in sparse arraysif ( i in array && array[ i ] === elem ) {return i;}}}return -1; }
3. jQuery.merge(first, second)
用于合并兩個數(shù)組的元素到第一個數(shù)組。
第一個參數(shù)也可以時類數(shù)組對象(即必須有整型屬性length值)。
第二個參數(shù)可以是數(shù)組,類數(shù)組或者有連續(xù)整型屬性的對象。
merge: function( first, second ) {var i = first.length,j = 0;if ( typeof second.length === "number" ) {for ( var l = second.length; j < l; j++ ) {first[ i++ ] = second[ j ];}} else {while ( second[j] !== undefined ) {first[ i++ ] = second[ j++ ];}}first.length = i;return first;},
4.jQuery.grep(array, function(elemOfArray, indexInArray)[, invert])
用于查找數(shù)組中滿足過濾函數(shù)的元素,原數(shù)組不受影響。如果invert沒有傳入,或者傳入false.
元素只有在過濾函數(shù)返回true時,才會被保存在最終的結(jié)果中。如果傳入true情況相反。
grep: function( elems, callback, inv ) {var ret = [], retVal;inv = !!inv;// Go through the array, only saving the items// that pass the validator functionfor ( var i = 0, length = elems.length; i < length; i++ ) {retVal = !!callback( elems[ i ], i );if ( inv !== retVal ) {ret.push( elems[ i ] );}}return ret;},
8. jQuery.proxy()
// Bind a function to a context, optionally partially applying any// arguments.proxy: function( fn, context ) {if ( typeof context === "string" ) {var tmp = fn[ context ];context = fn;fn = tmp;}// Quick check to determine if target is callable, in the spec// this throws a TypeError, but we will just return undefined.if ( !jQuery.isFunction( fn ) ) {return undefined;}// Simulated bindvar args = slice.call( arguments, 2 ),proxy = function() {return fn.apply( context, args.concat( slice.call( arguments ) ) );};// Set the guid of unique handler to the same of original handler, so it can be removedproxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;return proxy;},
9. jQuery.access()
為集合中的元素設(shè)置一個或者多個屬性值,或者讀取第一個元素的屬性值。
?
轉(zhuǎn)載于:https://www.cnblogs.com/Shadowplay/p/9773439.html
總結(jié)
以上是生活随笔為你收集整理的jquery 1.7.2源码解析(二)构造jquery对象的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为啥《若能与你共乘海浪之上》突然不在七号
- 下一篇: pandas学习之Series结构