Jquery source code series: append method implementation process
No1:
// Define a local copy of jQuery
Var jQuery = function (selector, context ){
// The jQuery object is actually just the init constructor 'enabled'
Return new jQuery. fn.Init(Selector, context, rootjQuery); // call the second-step init Method
},
No2:
JQuery. fn = jQuery. prototype = {
Constructor: jQuery,
Init: Function (selector, context, rootjQuery ){
Var match, elem, ret, doc;
// Handle $ (""), $ (null), or $ (undefined)
If (! Selector ){
Return this;
}
// Handle $ (DOMElement)
If (selector. nodeType ){
This. context = this [0] = selector;
This. length = 1;
Return this;
}
// The body element only exists once, optimize finding it
If (selector = "body "&&! Context & document. body ){
This. context = document;
This [0] = document. body;
This. selector = selector;
This. length = 1;
Return this;
}
// Handle HTML strings
If (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 check
Match = [null, selector, null];
} Else {
Match = quickExpr.exe c (selector );
}
// Verify a match, and that no context was specified for # id
If (match & (match [1] |! Context )){
// HANDLE: $ (html)-> $ (array)
If (match [1]) {
Context = context instanceof jQuery? Context [0]: context;
Doc = (context? Context. ownerDocument | context: document );
// If a single string is passed in and it's a single tag
// Just do a createElement and skip the rest
Ret = rsingleTag.exe c (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 = jQuery. buildFragment ([match [1], [doc]);
Selector = (ret. cacheable? JQuery. clone (ret. fragment): ret. fragment). childNodes;
}
Return jQuery. merge (this, selector );
// 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 #6963
If (elem & elem. parentNode ){
// Handle the case where IE and Opera return items
// By name instead of ID
If (elem. id! = Match [2]) {
Return rootjQuery. find (selector );
}
// Otherwise, we inject the element directly into the jQuery object
This. length = 1;
This [0] = elem;
}
This. context = document;
This. selector = selector;
Return this;
}
// 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 );
}
// HANDLE: $ (function)
// Shortcut for document ready
} Else if (jQuery. isFunction (selector )){
Return rootjQuery. ready (selector );
}
If (selector. selector! = Undefined ){
This. selector = selector. selector;
This. context = selector. context;
}
Return jQuery. makeArray (selector, this );
},
// Start with an empty selector
Selector :"",
// The current version of jQuery being used
Jquery: "1.7.1 ",
// The default length of a jQuery object is 0
Length: 0,
// The number of elements contained in the matched element set
Size: function (){
Return this. length;
},
ToArray: function (){
Return slice. call (this, 0 );
},
// Get the Nth element in the matched element set OR
// Get the whole matched element set as a clean array
Get: function (num ){
Return num = null?
// Return a 'clean' array
This. toArray ():
// Return just the object
(Num <0? This [this. length + num]: this [num]);
},
// Take an array of elements and push it onto the stack
// (Returning the new matched element set)
PushStack: function (elems, name, selector ){
// Build a new jQuery matched element set
Var 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 set
Return ret;
},
// Execute a callback for every element in the matched set.
// (You can seed the arguments with an array of args, but this is
// Only used internally .)
Each: function (callback, args ){
Return jQuery. each (this, callback, args );
},
Ready: function (fn ){
// Attach the listeners
JQuery. bindReady ();
// Add the callback
ReadyList. add (fn );
Return this;
},
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 (","));
},
Map: function (callback ){
Return this. pushStack (jQuery. map (this, function (elem, I ){
Return callback. call (elem, I, elem );
}));
},
End: function (){
Return this. prevObject | this. constructor (null );
},
// For internal use only.
// Behaves like an Array's method, not like a jQuery method.
Push: push,
Sort: []. sort,
Splice: []. splice
};
No3: entry to append
JQuery. fn. extend ({
Text: function (text ){
If (jQuery. isFunction (text )){
Return this. each (function (I ){
Var self = jQuery (this );
Self. text (text. call (this, I, self. text ()));
});
}
If (typeof text! = "Object" & text! = Undefined ){
Return this. empty (). append (this [0] & this [0]. ownerDocument | document). createTextNode (text ));
}
Return jQuery. text (this );
},
WrapAll: function (html ){
If (jQuery. isFunction (html )){
Return this. each (function (I ){
JQuery (this). wrapAll (html. call (this, I ));
});
}
If (this [0]) {
// The elements to wrap the target around
Var wrap = jQuery (html, this [0]. ownerDocument). eq (0). clone (true );
If (this [0]. parentNode ){
Wrap. insertBefore (this [0]);
}
Wrap. map (function (){
Var elem = this;
While (elem. firstChild & elem. firstChild. nodeType = 1 ){
Elem = elem. firstChild;
}
Return elem;
}). Append (this );
}
Return this;
},
WrapInner: function (html ){
If (jQuery. isFunction (html )){
Return this. each (function (I ){
JQuery (this). wrapInner (html. call (this, I ));
});
}
Return this. each (function (){
Var self = jQuery (this ),
Contents = self. contents ();
If (contents. length ){
Contents. wrapAll (html );
} Else {
Self. append (html );
}
});
},
Wrap: function (html ){
Var isFunction = jQuery. isFunction (html );
Return this. each (function (I ){
JQuery (this). wrapAll (isFunction? Html. call (this, I): html );
});
},
Unwrap: function (){
Return this. parent (). each (function (){
If (! JQuery. nodeName (this, "body ")){
JQuery (this). replaceWith (this. childNodes );
}
}). End ();
},
Append: function (){
Return this. domManip (arguments, true, function (elem ){
If (this. nodeType = 1 ){
This. appendChild (elem );
}
});
},
Prepend: function (){
Return this. domManip (arguments, true, function (elem ){
If (this. nodeType = 1 ){
This. insertBefore (elem, this. firstChild );
}
});
},
Before: function (){
If (this [0] & this [0]. parentNode ){
Return this. domManip (arguments, false, function (elem ){
This. parentNode. insertBefore (elem, this );
});
} Else if (arguments. length ){
Var set = jQuery. clean (arguments );
Set. push. apply (set, this. toArray ());
Return this. pushStack (set, "before", arguments );
}
},
After: function (){
If (this [0] & this [0]. parentNode ){
Return this. domManip (arguments, false, function (elem ){
This. parentNode. insertBefore (elem, this. nextSibling );
});
} Else if (arguments. length ){
Var set = this. pushStack (this, "after", arguments );
Set. push. apply (set, jQuery. clean (arguments ));
Return set;
}
},
// KeepData is for internal use only -- do not document
Remove: function (selector, keepData ){
For (var I = 0, elem; (elem = this [I])! = Null; I ++ ){
If (! Selector | jQuery. filter (selector, [elem]). length ){
If (! KeepData & elem. nodeType = 1 ){
JQuery. cleanData (elem. getElementsByTagName ("*"));
JQuery. cleanData ([elem]);
}
If (elem. parentNode ){
Elem. parentNode. removeChild (elem );
}
}
}
Return this;
},
Empty: function (){
For (var I = 0, elem; (elem = this [I])! = Null; I ++ ){
// Remove element nodes and prevent memory leaks
If (elem. nodeType = 1 ){
JQuery. cleanData (elem. getElementsByTagName ("*"));
}
// Remove any remaining nodes
While (elem. firstChild ){
Elem. removeChild (elem. firstChild );
}
}
Return this;
},
Clone: function (dataAndEvents, deepDataAndEvents ){
DataAndEvents = null? False: dataAndEvents;
DeepDataAndEvents = null? DataAndEvents: deepDataAndEvents;
Return this. map (function (){
Return jQuery. clone (this, dataAndEvents, deepDataAndEvents );
});
},
Html: function (value ){
If (value = undefined ){
Return this [0] & this [0]. nodeType = 1?
This [0]. innerHTML. replace (rinlinejQuery ,""):
Null;
// See if we can take a shortcut and just use innerHTML
} Else if (typeof value = "string "&&! RnoInnerhtml. test (value )&&
(JQuery. support. leadingWhitespace |! RleadingWhitespace. test (value ))&&
! WrapMap [(rtagName.exe c (value) | ["", ""]) [1]. toLowerCase ()]) {
Value = value. replace (rxhtmlTag, "<$1> ");
Try {
For (var I = 0, l = this. length; I <l; I ++ ){
// Remove element nodes and prevent memory leaks
If (this [I]. nodeType = 1 ){
JQuery. cleanData (this [I]. getElementsByTagName ("*"));
This [I]. innerHTML = value;
}
}
// If using innerHTML throws an exception, use the fallback method
} Catch (e ){
This. empty (). append (value );
}
} Else if (jQuery. isFunction (value )){
This. each (function (I ){
Var self = jQuery (this );
Self.html (value. call (this, I, self.html ()));
});
} Else {
This. empty (). append (value );
}
Return this;
},
ReplaceWith: function (value ){
If (this [0] & this [0]. parentNode ){
// Make sure that the elements are removed from the DOM before they are inserted
// This can help fix replacing a parent with child elements
If (jQuery. isFunction (value )){
Return this. each (function (I ){
Var self = jQuery (this), old = self.html ();
Self. replaceWith (value. call (this, I, old ));
});
}
If (typeof value! = "String "){
Value = jQuery (value). detach ();
}
Return this. each (function (){
Var next = this. nextSibling,
Parent = this. parentNode;
JQuery (this). remove ();
If (next ){
JQuery (next). before (value );
} Else {
JQuery (parent). append (value );
}
});
} Else {
Return this. length?
This. pushStack (jQuery. isFunction (value )? Value (): value), "replaceWith", value ):
This;
}
},
Detach: function (selector ){
Return this. remove (selector, true );
},
DomManip: Function (args, table, callback ){
Var results, first, fragment, parent,
Value = args [0],
Scripts = [];
// We can't cloneNode fragments that contain checked, in WebKit
If (! JQuery. support. checkClone & arguments. length = 3 & typeof value = "string" & rchecked. test (value )){
Return this. each (function (){
JQuery (this). domManip (args, table, callback, true );
});
}
If (jQuery. isFunction (value )){
Return this. each (function (I ){
Var self = jQuery (this );
Args [0] = value. call (this, I, table? Self.html (): undefined );
Self.
DomManip(Args, table, callback );
});
}
If (this [0]) {
Parent = value & value. parentNode;
// If we're in a fragment, just use that instead of building a new one
If (jQuery. support. parentNode & parent. nodeType ===11 & parent. childNodes. length === this. length ){
Results = {fragment: parent };
} Else {
Results = jQuery.
BuildFragment(Args, this, scripts); // construct a new instance
}
Fragment = results. fragment;
If (fragment. childNodes. length = 1 ){
First = fragment. firstChild;
} Else {
First = fragment. firstChild;
}
If (first ){
Table = table & jQuery. nodeName (first, "tr ");
For (var I = 0, l = this. length, lastIndex = l-1; I <l; I ++ ){
Callback. call (
Table?
Root (this [I], first ):
This [I],
// Make sure that we do not leak memory by inadvertently discarding
// The original fragment (which might have attached data) instead
// Using it; in addition, use the original fragment object for the last
// Item instead of first because it can end up being emptied incorrectly
// In certain situations (Bug #8070 ).
// Fragments from the fragment cache must always be cloned and never used
// In place.
Results. cacheable | (l> 1 & I <lastIndex )?
JQuery. clone (fragment, true, true ):
Fragment
);
}
}
If (scripts. length ){
JQuery. each (scripts, evalScript );
}
}
Return this;
}
});
//BuildFragment Method
JQuery. buildFragment = function (args, nodes, scripts ){
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;
}
// 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 putOrElements 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.html 5 Clone |! Rnoshimcache. test (first ))){
Cacheable = true;
Cacheresults = jQuery. fragments [first];
If (cacheresults & cacheresults! = 1 ){
Fragment = cacheresults;
}
}
If (! Fragment ){
Fragment = doc. createDocumentFragment ();
JQuery. clean (args, doc, fragment, scripts );
}
If (cacheable ){
JQuery. fragments [first] = cacheresults? Fragment: 1;
}
Return {fragment: fragment, cacheable: cacheable };
};