Obviously, the implementation to achieve this step is quite complicated. This implementation is its init method, the real constructor of jQuery. Its functions are also upgraded with the version upgrade, and it is getting longer and longer.
Version 1.3 released on 2009-01-13
init: function( selector, context ) {
var match, elem, ret, doc;
//Handle blank string, null, undefined parameters (newly added), return a very pure Instance of
if ( !selector ) {
return this;
}
// Process node parameters and directly add attributes to the new instance
if ( selector.nodeType ) {
this.context = this[0] = selector;//Optimized writing
this.length = 1;
return this;
}
//Processing string parameters
if ( typeof selector === "string" ) {
// Determine whether it is an HTML fragment or an ID
match = quickExpr.exec( selector );
if ( match && (match[1] || !context) ) {
//If it is an HTML fragment
if ( match[1] ) {
//Get the document object
doc = (context ? context.ownerDocument || context : document);
// If it is a single tag, directly use document.createElement to create this node and put it into the array
ret = rsingleTag.exec( selector );
if ( ret ) {
//If followed by Pure JS object, add corresponding attributes or styles to this node
if ( jQuery.isPlainObject( context ) ) {
selector = [ document.createElement( ret[1] ) ];
jQuery. fn.attr.call( selector, context, true );
} else {
selector = [ doc.createElement( ret[1] ) ];
}
} else {
/ /Change buildFragment to generate node collection (NodeList)
ret = buildFragment( [ match[1] ], [ doc ] );
selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret .fragment).childNodes;
}
} else {
// If it is an ID, search for this element, and if found, put it into an empty array
elem = document.getElementById( match[2] );
if ( elem ) {
// Deal with the bug of confusion between ID and NAME in IE and Opera
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}
//Some optimizations have also been done here. It turns out that it is stupid to generate another jQuery instance
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
}
// If the character is a very simple label selector, there is basically no need to go Sizzle route, getElementsByTagName directly, very good optimization
} else if ( !context && /^w $/.test( selector ) ) {
this.selector = selector;
this.context = document;
selector = document.getElementsByTagName( selector );
// If the second parameter does not exist or is a jQuery object, then use it or rootjQuery to call find to find the target node (take the Sizzle route)
} else if ( !context || context.jquery ) {
return (context || rootjQuery).find( selector );
// HANDLE: $(expr, context)
// (which is just equivalent to : $(context).find(expr)
} else {
//If the second parameter has been specified as an element node, convert it to a jQuery object, take the Sizzle route
return jQuery( context ). find( selector );
}
// Process function parameters directly domReady
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
//Handle the jQuery object parameters and simply assign its two properties to the new instance
if (selector.selector !== undefined) {
this.selector = selector.selector;
this .context = selector.context;
}
//Some modifications have been made here, because makeArray can accept the second parameter (can be an array or array-like, which is equivalent to a merge operation)
return jQuery.isArray( selector ) ?
this.setArray( selector ) ://Use push method internally to quickly turn an ordinary object into an array-like object
jQuery.makeArray( selector, this );
} , <🎜> >The code is as follows:
init: function( selector, context ) {
var match, elem, ret, doc;
// Handle blank string, null, undefined parameters
if ( !selector ) {
return this;
}
// Process node parameters
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1 ;
return this;
}
// Process body parameters (new)
if ( selector === "body" && !context ) {
this.context = document;
this[0] = document.body;
this.selector = "body";
this.length = 1;
return this;
}
// Processing string parameters , divided into seven situations:
//①Single label, with object attribute package---> jQuery.merge
//②Single label, without object attribute package---> attr jQuery.merge
//③Complex HTML fragment---> buildFragment jQuery.merge
//④ID selector, which is different from the ID of the found element---> getElementById Sizzle pushStack
//⑤ID selection Device, the same as the ID of the found element ---> getElementById simple attribute addition
//⑥ tag selector ---> getElementsByTagName jQuery.merge
///⑦ other CSS expressions ---> ; 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 );
}
// Process function parameters directly domReady
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
//Processing jQuery object parameters
if (selector.selector !== undefined) {
this.selector = selector.selector;
this.context = selector.context;
}
//Whether it is an array or an array-like (such as NodeList), use jQuery.makeArray to add new elements to the instance
return jQuery.makeArray( selector, this );
},
Attached are the makeArray method and merge method. The merge method is so amazing.
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 < l; j ) {
first[ i ] = second[ j ];
}
} else {
while ( second[j] !== undefined ) {
first[ i ] = second[ j ];
}
}
first.length = i;
return first;
},
2011-01 Version 1.5 released on -23 has little change in the init method from 1.42: only two changes have been made:
//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 );//The purpose is not to generate new instances
Jquery 1.6 released on 2011-05-02 has not changed much, except for a stricter judgment on HTML fragments:
// 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 check
match = [ null, selector, null ];
} else {
match = quickExpr.exec( selector );
}
In general, the structure of jQuery The instrument has been made very perfect, and it has basically reached the point where "nothing can be changed". But to ensure its efficient operation, we also need some knowledge of selectors and understanding of the operation of the buildFragment method, because these two are too commonly used, but they are also the most performance-consuming.