第五节:JQuery框架源码简析(3)

(续2)

9、DOM

我们将jQuery有关DOM模块的代码放在文件jquery.extend.dom.js中。

function jQuery_extend_dom(jQuery){

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 = dataAndEvents == null ? false : dataAndEvents;

deepDataAndEvents = 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.exec( value ) || ["", ""])[1].toLowerCase() ] ) {

value = value.replace(rxhtmlTag, "<$1></$2>");

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(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 && parent.nodeType === 11 && parent.childNodes.length === this.length ) {

results = { fragment: parent };

} else {

results = jQuery.buildFragment( args, this, scripts );

}

fragment = results.fragment;

if ( fragment.childNodes.length === 1 ) {

first = fragment = 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 of

// 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;

}

});

jQuery.extend({

clone: function( elem, dataAndEvents, deepDataAndEvents ) {

var srcElements,

destElements,

i,

// IE<=8 does not properly clone detached, unknown element nodes

clone = jQuery.support.html5Clone || !rnoshimcache.test( "<" + elem.nodeName ) ?

elem.cloneNode( true ) :

shimCloneNode( elem );

if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&

(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {

// IE copies events bound via attachEvent when using cloneNode.

// Calling detachEvent on the clone will also remove the events

// from the original. In order to get around this, we use some

// proprietary methods to clear the events. Thanks to MooTools

// guys for this hotness.

cloneFixAttributes( elem, clone );

// Using Sizzle here is crazy slow, so we use getElementsByTagName instead

srcElements = getAll( elem );

destElements = getAll( clone );

// Weird iteration because IE will replace the length property

// with an element if you are cloning the body and one of the

// elements on the page has a name or id of "length"

for ( i = 0; srcElements[i]; ++i ) {

// Ensure that the destination node is not null; Fixes #9587

if ( destElements[i] ) {

cloneFixAttributes( srcElements[i], destElements[i] );

}

}

}

// Copy the events from the original to the clone

if ( dataAndEvents ) {

cloneCopyEvent( elem, clone );

if ( deepDataAndEvents ) {

srcElements = getAll( elem );

destElements = getAll( clone );

for ( i = 0; srcElements[i]; ++i ) {

cloneCopyEvent( srcElements[i], destElements[i] );

}

}

}

srcElements = destElements = null;

// Return the cloned set

return clone;

},

clean: function( elems, context, fragment, scripts ) {

var checkScriptType;

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;

}

var ret = [], j;

for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {

if ( typeof elem === "number" ) {

elem += "";

}

if ( !elem ) {

continue;

}

// Convert html string into DOM nodes

if ( typeof elem === "string" ) {

if ( !rhtml.test( elem ) ) {

elem = context.createTextNode( elem );

} else {

// Fix "XHTML"-style tags in all browsers

elem = elem.replace(rxhtmlTag, "<$1></$2>");

// Trim whitespace, otherwise indexOf won‘t work as expected

var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),

wrap = wrapMap[ tag ] || wrapMap._default,

depth = wrap[0],

div = context.createElement("div");

// Append wrapper element to unknown element safe doc fragment

if ( 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 );

}

// 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;

}

// Remove IE‘s autoinserted <tbody> from table fragments

if ( !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 ] );

}

}

}

// IE completely kills leading whitespace when innerHTML is used

if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {

div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );

}

elem = div.childNodes;

}

}

// Resets defaultChecked for any radios and checkboxes

// about to be appended to the DOM in IE 6/7 (#8060)

var len;

if ( !jQuery.support.appendChecked ) {

if ( elem[0] && typeof (len = elem.length) === "number" ) {

for ( j = 0; j < len; j++ ) {

findInputs( elem[j] );

}

} else {

findInputs( elem );

}

}

if ( elem.nodeType ) {

ret.push( elem );

} else {

ret = jQuery.merge( ret, elem );

}

}

if ( fragment ) {

checkScriptType = function( elem ) {

return !elem.type || rscriptType.test( elem.type );

};

for ( i = 0; ret[i]; i++ ) {

if ( scripts && 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 ) {

var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType );

ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );

}

fragment.appendChild( ret[i] );

}

}

}

return ret;

},

cleanData: function( elems ) {

var data, id,

cache = jQuery.cache,

special = jQuery.event.special,

deleteExpando = jQuery.support.deleteExpando;

for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {

if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {

continue;

}

id = elem[ jQuery.expando ];

if ( id ) {

data = cache[ id ];

if ( data && data.events ) {

for ( var type in data.events ) {

if ( special[ type ] ) {

jQuery.event.remove( elem, type );

// This is a shortcut to avoid jQuery.event.remove‘s overhead

} else {

jQuery.removeEvent( elem, type, data.handle );

}

}

// Null the DOM reference to avoid IE6/7/8 leak (#7054)

if ( data.handle ) {

data.handle.elem = null;

}

}

if ( deleteExpando ) {

delete elem[ jQuery.expando ];

} else if ( elem.removeAttribute ) {

elem.removeAttribute( jQuery.expando );

}

delete cache[ id ];

}

}

}

});

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 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;

}

}

if ( !fragment ) {

fragment = doc.createDocumentFragment();

jQuery.clean( args, doc, fragment, scripts );

}

if ( cacheable ) {

jQuery.fragments[ first ] = cacheresults ? fragment : 1;

}

return { fragment: fragment, cacheable: cacheable };

};

jQuery.fragments = {};

}

10、事件系统

我们将jQuery事件系统的相关代码放在文件jquery.extend.dom.js中。

function jQuery_extend_event(jQuery){

var rformElems = /^(?:textarea|input|select)$/i,

rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,

rhoverHack = /\bhover(\.\S+)?\b/,

rkeyEvent = /^key/,

rmouseEvent = /^(?:mouse|contextmenu)|click/,

rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,

rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,

quickParse = function( selector ) {

var quick = rquickIs.exec( selector );

if ( quick ) {

//   0  1    2   3

// [ _, tag, id, class ]

quick[1] = ( quick[1] || "" ).toLowerCase();

quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );

}

return quick;

},

quickIs = function( elem, m ) {

var attrs = elem.attributes || {};

return (

(!m[1] || elem.nodeName.toLowerCase() === m[1]) &&

(!m[2] || (attrs.id || {}).value === m[2]) &&

(!m[3] || m[3].test( (attrs[ "class" ] || {}).value ))

);

},

hoverHack = function( events ) {

return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );

};

/*

* Helper functions for managing events -- not part of the public interface.

* Props to Dean Edwards‘ addEvent library for many of the ideas.

*/

jQuery.event = {

add: function( elem, types, handler, data, selector ) {

var elemData, eventHandle, events,

t, tns, type, namespaces, handleObj,

handleObjIn, quick, handlers, special;

// Don‘t attach events to noData or text/comment nodes (allow plain objects tho)

if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {

return;

}

// Caller can pass in an object of custom data in lieu of the handler

if ( handler.handler ) {

handleObjIn = handler;

handler = handleObjIn.handler;

}

// Make sure that the handler has a unique ID, used to find/remove it later

if ( !handler.guid ) {

handler.guid = jQuery.guid++;

}

// Init the element‘s event structure and main handler, if this is the first

events = elemData.events;

if ( !events ) {

elemData.events = events = {};

}

eventHandle = elemData.handle;

if ( !eventHandle ) {

elemData.handle = eventHandle = function( e ) {

// Discard the second event of a jQuery.event.trigger() and

// when an event is called after a page has unloaded

return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?

jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :

undefined;

};

// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events

eventHandle.elem = elem;

}

// Handle multiple events separated by a space

// jQuery(...).bind("mouseover mouseout", fn);

types = jQuery.trim( hoverHack(types) ).split( " " );

for ( t = 0; t < types.length; t++ ) {

tns = rtypenamespace.exec( types[t] ) || [];

type = tns[1];

namespaces = ( tns[2] || "" ).split( "." ).sort();

// If event changes its type, use the special event handlers for the changed type

special = jQuery.event.special[ type ] || {};

// If selector defined, determine special event api type, otherwise given type

type = ( selector ? special.delegateType : special.bindType ) || type;

// Update special based on newly reset type

special = jQuery.event.special[ type ] || {};

// handleObj is passed to all event handlers

handleObj = jQuery.extend({

type: type,

origType: tns[1],

data: data,

handler: handler,

guid: handler.guid,

selector: selector,

quick: quickParse( selector ),

namespace: namespaces.join(".")

}, handleObjIn );

// Init the event handler queue if we‘re the first

handlers = events[ type ];

if ( !handlers ) {

handlers = events[ type ] = [];

handlers.delegateCount = 0;

// Only use addEventListener/attachEvent if the special events handler returns false

if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {

// Bind the global event handler to the element

if ( elem.addEventListener ) {

elem.addEventListener( type, eventHandle, false );

} else if ( elem.attachEvent ) {

elem.attachEvent( "on" + type, eventHandle );

}

}

}

if ( special.add ) {

special.add.call( elem, handleObj );

if ( !handleObj.handler.guid ) {

handleObj.handler.guid = handler.guid;

}

}

// Add to the element‘s handler list, delegates in front

if ( selector ) {

handlers.splice( handlers.delegateCount++, 0, handleObj );

} else {

handlers.push( handleObj );

}

// Keep track of which events have ever been used, for event optimization

jQuery.event.global[ type ] = true;

}

// Nullify elem to prevent memory leaks in IE

elem = null;

},

global: {},

// Detach an event or set of events from an element

remove: function( elem, types, handler, selector, mappedTypes ) {

var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),

t, tns, type, origType, namespaces, origCount,

j, events, special, handle, eventType, handleObj;

if ( !elemData || !(events = elemData.events) ) {

return;

}

// Once for each type.namespace in types; type may be omitted

types = jQuery.trim( hoverHack( types || "" ) ).split(" ");

for ( t = 0; t < types.length; t++ ) {

tns = rtypenamespace.exec( types[t] ) || [];

type = origType = tns[1];

namespaces = tns[2];

// Unbind all events (on this namespace, if provided) for the element

if ( !type ) {

for ( type in events ) {

jQuery.event.remove( elem, type + types[ t ], handler, selector, true );

}

continue;

}

special = jQuery.event.special[ type ] || {};

type = ( selector? special.delegateType : special.bindType ) || type;

eventType = events[ type ] || [];

origCount = eventType.length;

namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;

// Remove matching events

for ( j = 0; j < eventType.length; j++ ) {

handleObj = eventType[ j ];

if ( ( mappedTypes || origType === handleObj.origType ) &&

( !handler || handler.guid === handleObj.guid ) &&

( !namespaces || namespaces.test( handleObj.namespace ) ) &&

( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {

eventType.splice( j--, 1 );

if ( handleObj.selector ) {

eventType.delegateCount--;

}

if ( special.remove ) {

special.remove.call( elem, handleObj );

}

}

}

// Remove generic event handler if we removed something and no more handlers exist

// (avoids potential for endless recursion during removal of special event handlers)

if ( eventType.length === 0 && origCount !== eventType.length ) {

if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {

jQuery.removeEvent( elem, type, elemData.handle );

}

delete events[ type ];

}

}

// Remove the expando if it‘s no longer used

if ( jQuery.isEmptyObject( events ) ) {

handle = elemData.handle;

if ( handle ) {

handle.elem = null;

}

// removeData also checks for emptiness and clears the expando if empty

// so use it instead of delete

jQuery.removeData( elem, [ "events", "handle" ], true );

}

},

// Events that are safe to short-circuit if no handlers are attached.

// Native DOM events should not be added, they may have inline handlers.

customEvent: {

"getData": true,

"setData": true,

"changeData": true

},

trigger: function( event, data, elem, onlyHandlers ) {

// Don‘t do events on text and comment nodes

if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {

return;

}

// Event object or event type

var type = event.type || event,

namespaces = [],

cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;

// focus/blur morphs to focusin/out; ensure we‘re not firing them right now

if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {

return;

}

if ( type.indexOf( "!" ) >= 0 ) {

// Exclusive events trigger only for the exact event (no namespaces)

type = type.slice(0, -1);

exclusive = true;

}

if ( type.indexOf( "." ) >= 0 ) {

// Namespaced trigger; create a regexp to match event type in handle()

namespaces = type.split(".");

type = namespaces.shift();

namespaces.sort();

}

if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {

// No jQuery handlers for this event type, and it can‘t have inline handlers

return;

}

// Caller can pass in an Event, Object, or just an event type string

event = typeof event === "object" ?

// jQuery.Event object

event[ jQuery.expando ] ? event :

// Object literal

new jQuery.Event( type, event ) :

// Just the event type (string)

new jQuery.Event( type );

event.type = type;

event.isTrigger = true;

event.exclusive = exclusive;

event.namespace = namespaces.join( "." );

event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;

ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";

// Handle a global trigger

if ( !elem ) {

// TODO: Stop taunting the data cache; remove global events and always attach to document

cache = jQuery.cache;

for ( i in cache ) {

if ( cache[ i ].events && cache[ i ].events[ type ] ) {

jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );

}

}

return;

}

// Clean up the event in case it is being reused

event.result = undefined;

if ( !event.target ) {

event.target = elem;

}

// Clone any incoming data and prepend the event, creating the handler arg list

data = data != null ? jQuery.makeArray( data ) : [];

data.unshift( event );

// Allow special events to draw outside the lines

special = jQuery.event.special[ type ] || {};

if ( special.trigger && special.trigger.apply( elem, data ) === false ) {

return;

}

// Determine event propagation path in advance, per W3C events spec (#9951)

// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)

eventPath = [[ elem, special.bindType || type ]];

if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {

bubbleType = special.delegateType || type;

cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;

old = null;

for ( ; cur; cur = cur.parentNode ) {

eventPath.push([ cur, bubbleType ]);

old = cur;

}

// Only add window if we got to document (e.g., not plain obj or detached DOM)

if ( old && old === elem.ownerDocument ) {

eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);

}

}

// Fire handlers on the event path

for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {

cur = eventPath[i][0];

event.type = eventPath[i][1];

handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );

if ( handle ) {

handle.apply( cur, data );

}

// Note that this is a bare JS function and not a jQuery handler

handle = ontype && cur[ ontype ];

if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {

event.preventDefault();

}

}

event.type = type;

// If nobody prevented the default action, do it now

if ( !onlyHandlers && !event.isDefaultPrevented() ) {

if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&

!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {

// Call a native DOM method on the target with the same name name as the event.

// Can‘t use an .isFunction() check here because IE6/7 fails that test.

// Don‘t do default actions on window, that‘s where global variables be (#6170)

// IE<9 dies on focus/blur to hidden element (#1486)

if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {

// Don‘t re-trigger an onFOO event when we call its FOO() method

old = elem[ ontype ];

if ( old ) {

elem[ ontype ] = null;

}

// Prevent re-triggering of the same event, since we already bubbled it above

jQuery.event.triggered = type;

elem[ type ]();

jQuery.event.triggered = undefined;

if ( old ) {

elem[ ontype ] = old;

}

}

}

}

return event.result;

},

dispatch: function( event ) {

// Make a writable jQuery.Event from the native event object

event = jQuery.event.fix( event || window.event );

var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),

delegateCount = handlers.delegateCount,

args = [].slice.call( arguments, 0 ),

run_all = !event.exclusive && !event.namespace,

handlerQueue = [],

i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;

// Use the fix-ed jQuery.Event rather than the (read-only) native event

args[0] = event;

event.delegateTarget = this;

// Determine handlers that should run if there are delegated events

// Avoid disabled elements in IE (#6911) and non-left-click bubbling in Firefox (#3861)

if ( delegateCount && !event.target.disabled && !(event.button && event.type === "click") ) {

// Pregenerate a single jQuery object for reuse with .is()

jqcur = jQuery(this);

jqcur.context = this.ownerDocument || this;

for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {

selMatch = {};

matches = [];

jqcur[0] = cur;

for ( i = 0; i < delegateCount; i++ ) {

handleObj = handlers[ i ];

sel = handleObj.selector;

if ( selMatch[ sel ] === undefined ) {

selMatch[ sel ] = (

handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )

);

}

if ( selMatch[ sel ] ) {

matches.push( handleObj );

}

}

if ( matches.length ) {

handlerQueue.push({ elem: cur, matches: matches });

}

}

}

// Add the remaining (directly-bound) handlers

if ( handlers.length > delegateCount ) {

handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });

}

// Run delegates first; they may want to stop propagation beneath us

for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {

matched = handlerQueue[ i ];

event.currentTarget = matched.elem;

for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {

handleObj = matched.matches[ j ];

// Triggered event must either 1) be non-exclusive and have no namespace, or

// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).

if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {

event.data = handleObj.data;

event.handleObj = handleObj;

ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )

.apply( matched.elem, args );

if ( ret !== undefined ) {

event.result = ret;

if ( ret === false ) {

event.preventDefault();

event.stopPropagation();

}

}

}

}

}

return event.result;

},

// Includes some event props shared by KeyEvent and MouseEvent

// *** attrChange attrName relatedNode srcElement  are not normalized, non-W3C, deprecated, will be removed in 1.8 ***

props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),

fixHooks: {},

keyHooks: {

props: "char charCode key keyCode".split(" "),

filter: function( event, original ) {

// Add which for key events

if ( event.which == null ) {

event.which = original.charCode != null ? original.charCode : original.keyCode;

}

return event;

}

},

mouseHooks: {

props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),

filter: function( event, original ) {

var eventDoc, doc, body,

button = original.button,

fromElement = original.fromElement;

// Calculate pageX/Y if missing and clientX/Y available

if ( event.pageX == null && original.clientX != null ) {

eventDoc = event.target.ownerDocument || document;

doc = eventDoc.documentElement;

body = eventDoc.body;

event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );

event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );

}

// Add relatedTarget, if necessary

if ( !event.relatedTarget && fromElement ) {

event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;

}

// Add which for click: 1 === left; 2 === middle; 3 === right

// Note: button is not normalized, so don‘t use it

if ( !event.which && button !== undefined ) {

event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );

}

return event;

}

},

fix: function( event ) {

if ( event[ jQuery.expando ] ) {

return event;

}

// Create a writable copy of the event object and normalize some properties

var i, prop,

originalEvent = event,

fixHook = jQuery.event.fixHooks[ event.type ] || {},

copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;

event = jQuery.Event( originalEvent );

for ( i = copy.length; i; ) {

prop = copy[ --i ];

event[ prop ] = originalEvent[ prop ];

}

// Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)

if ( !event.target ) {

event.target = originalEvent.srcElement || document;

}

// Target should not be a text node (#504, Safari)

if ( event.target.nodeType === 3 ) {

event.target = event.target.parentNode;

}

// For mouse/key events; add metaKey if it‘s not there (#3368, IE6/7/8)

if ( event.metaKey === undefined ) {

event.metaKey = event.ctrlKey;

}

return fixHook.filter? fixHook.filter( event, originalEvent ) : event;

},

special: {

ready: {

// Make sure the ready event is setup

setup: jQuery.bindReady

},

load: {

// Prevent triggered image.load events from bubbling to window.load

noBubble: true

},

focus: {

delegateType: "focusin"

},

blur: {

delegateType: "focusout"

},

beforeunload: {

setup: function( data, namespaces, eventHandle ) {

// We only want to do this special case on windows

if ( jQuery.isWindow( this ) ) {

this.onbeforeunload = eventHandle;

}

},

teardown: function( namespaces, eventHandle ) {

if ( this.onbeforeunload === eventHandle ) {

this.onbeforeunload = null;

}

}

}

},

simulate: function( type, elem, event, bubble ) {

// Piggyback on a donor event to simulate a different one.

// Fake originalEvent to avoid donor‘s stopPropagation, but if the

// simulated event prevents default then we do the same on the donor.

var e = jQuery.extend(

new jQuery.Event(),

event,

{ type: type,

isSimulated: true,

originalEvent: {}

}

);

if ( bubble ) {

jQuery.event.trigger( e, null, elem );

} else {

jQuery.event.dispatch.call( elem, e );

}

if ( e.isDefaultPrevented() ) {

event.preventDefault();

}

}

};

// Some plugins are using, but it‘s undocumented/deprecated and will be removed.

// The 1.7 special event interface should provide all the hooks needed now.

jQuery.event.handle = jQuery.event.dispatch;

jQuery.removeEvent = document.removeEventListener ?

function( elem, type, handle ) {

if ( elem.removeEventListener ) {

elem.removeEventListener( type, handle, false );

}

} :

function( elem, type, handle ) {

if ( elem.detachEvent ) {

elem.detachEvent( "on" + type, handle );

}

};

jQuery.Event = function( src, props ) {

// Allow instantiation without the ‘new‘ keyword

if ( !(this instanceof jQuery.Event) ) {

return new jQuery.Event( src, props );

}

// Event object

if ( src && src.type ) {

this.originalEvent = src;

this.type = src.type;

// Events bubbling up the document may have been marked as prevented

// by a handler lower down the tree; reflect the correct value.

this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||

src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;

// Event type

} else {

this.type = src;

}

// Put explicitly provided properties onto the event object

if ( props ) {

jQuery.extend( this, props );

}

// Create a timestamp if incoming event doesn‘t have one

this.timeStamp = src && src.timeStamp || jQuery.now();

// Mark it as fixed

this[ jQuery.expando ] = true;

};

function returnFalse() {

return false;

}

function returnTrue() {

return true;

}

// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding

// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html

jQuery.Event.prototype = {

preventDefault: function() {

this.isDefaultPrevented = returnTrue;

var e = this.originalEvent;

if ( !e ) {

return;

}

// if preventDefault exists run it on the original event

if ( e.preventDefault ) {

e.preventDefault();

// otherwise set the returnValue property of the original event to false (IE)

} else {

e.returnValue = false;

}

},

stopPropagation: function() {

this.isPropagationStopped = returnTrue;

var e = this.originalEvent;

if ( !e ) {

return;

}

// if stopPropagation exists run it on the original event

if ( e.stopPropagation ) {

e.stopPropagation();

}

// otherwise set the cancelBubble property of the original event to true (IE)

e.cancelBubble = true;

},

stopImmediatePropagation: function() {

this.isImmediatePropagationStopped = returnTrue;

this.stopPropagation();

},

isDefaultPrevented: returnFalse,

isPropagationStopped: returnFalse,

isImmediatePropagationStopped: returnFalse

};

// Create mouseenter/leave events using mouseover/out and event-time checks

jQuery.each({

mouseenter: "mouseover",

mouseleave: "mouseout"

}, function( orig, fix ) {

jQuery.event.special[ orig ] = {

delegateType: fix,

bindType: fix,

handle: function( event ) {

var target = this,

related = event.relatedTarget,

handleObj = event.handleObj,

selector = handleObj.selector,

ret;

// For mousenter/leave call the handler if related is outside the target.

// NB: No relatedTarget if the mouse left/entered the browser window

if ( !related || (related !== target && !jQuery.contains( target, related )) ) {

event.type = handleObj.origType;

ret = handleObj.handler.apply( this, arguments );

event.type = fix;

}

return ret;

}

};

});

// IE submit delegation

if ( !jQuery.support.submitBubbles ) {

jQuery.event.special.submit = {

setup: function() {

// Only need this for delegated form submit events

if ( jQuery.nodeName( this, "form" ) ) {

return false;

}

// Lazy-add a submit handler when a descendant form may potentially be submitted

jQuery.event.add( this, "click._submit keypress._submit", function( e ) {

// Node name check avoids a VML-related crash in IE (#9807)

var elem = e.target,

form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;

if ( form && !form._submit_attached ) {

jQuery.event.add( form, "submit._submit", function( event ) {

// If form was submitted by the user, bubble the event up the tree

if ( this.parentNode && !event.isTrigger ) {

jQuery.event.simulate( "submit", this.parentNode, event, true );

}

});

form._submit_attached = true;

}

});

// return undefined since we don‘t need an event listener

},

teardown: function() {

// Only need this for delegated form submit events

if ( jQuery.nodeName( this, "form" ) ) {

return false;

}

// Remove delegated handlers; cleanData eventually reaps submit handlers attached above

jQuery.event.remove( this, "._submit" );

}

};

}

// IE change delegation and checkbox/radio fix

if ( !jQuery.support.changeBubbles ) {

jQuery.event.special.change = {

setup: function() {

if ( rformElems.test( this.nodeName ) ) {

// IE doesn‘t fire change on a check/radio until blur; trigger it on click

// after a propertychange. Eat the blur-change in special.change.handle.

// This still fires onchange a second time for check/radio after blur.

if ( this.type === "checkbox" || this.type === "radio" ) {

jQuery.event.add( this, "propertychange._change", function( event ) {

if ( event.originalEvent.propertyName === "checked" ) {

this._just_changed = true;

}

});

jQuery.event.add( this, "click._change", function( event ) {

if ( this._just_changed && !event.isTrigger ) {

this._just_changed = false;

jQuery.event.simulate( "change", this, event, true );

}

});

}

return false;

}

// Delegated event; lazy-add a change handler on descendant inputs

jQuery.event.add( this, "beforeactivate._change", function( e ) {

var elem = e.target;

if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {

jQuery.event.add( elem, "change._change", function( event ) {

if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {

jQuery.event.simulate( "change", this.parentNode, event, true );

}

});

elem._change_attached = true;

}

});

},

handle: function( event ) {

var elem = event.target;

// Swallow native change events from checkbox/radio, we already triggered them above

if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {

return event.handleObj.handler.apply( this, arguments );

}

},

teardown: function() {

jQuery.event.remove( this, "._change" );

return rformElems.test( this.nodeName );

}

};

}

// Create "bubbling" focus and blur events

if ( !jQuery.support.focusinBubbles ) {

jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {

// Attach a single capturing handler while someone wants focusin/focusout

var attaches = 0,

handler = function( event ) {

jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );

};

jQuery.event.special[ fix ] = {

setup: function() {

if ( attaches++ === 0 ) {

document.addEventListener( orig, handler, true );

}

},

teardown: function() {

if ( --attaches === 0 ) {

document.removeEventListener( orig, handler, true );

}

}

};

});

}

jQuery.fn.extend({

on: function( types, selector, data, fn, /*INTERNAL*/ one ) {

var origFn, type;

// Types can be a map of types/handlers

if ( typeof types === "object" ) {

// ( types-Object, selector, data )

if ( typeof selector !== "string" ) {

// ( types-Object, data )

data = selector;

selector = undefined;

}

for ( type in types ) {

this.on( type, selector, data, types[ type ], one );

}

return this;

}

if ( data == null && fn == null ) {

// ( types, fn )

fn = selector;

data = selector = undefined;

} else if ( fn == null ) {

if ( typeof selector === "string" ) {

// ( types, selector, fn )

fn = data;

data = undefined;

} else {

// ( types, data, fn )

fn = data;

data = selector;

selector = undefined;

}

}

if ( fn === false ) {

fn = returnFalse;

} else if ( !fn ) {

return this;

}

if ( one === 1 ) {

origFn = fn;

fn = function( event ) {

// Can use an empty set, since event contains the info

jQuery().off( event );

return origFn.apply( this, arguments );

};

// Use same guid so caller can remove using origFn

fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );

}

return this.each( function() {

jQuery.event.add( this, types, fn, data, selector );

});

},

one: function( types, selector, data, fn ) {

return this.on.call( this, types, selector, data, fn, 1 );

},

off: function( types, selector, fn ) {

if ( types && types.preventDefault && types.handleObj ) {

// ( event )  dispatched jQuery.Event

var handleObj = types.handleObj;

jQuery( types.delegateTarget ).off(

handleObj.namespace? handleObj.type + "." + handleObj.namespace : handleObj.type,

handleObj.selector,

handleObj.handler

);

return this;

}

if ( typeof types === "object" ) {

// ( types-object [, selector] )

for ( var type in types ) {

this.off( type, selector, types[ type ] );

}

return this;

}

if ( selector === false || typeof selector === "function" ) {

// ( types [, fn] )

fn = selector;

selector = undefined;

}

if ( fn === false ) {

fn = returnFalse;

}

return this.each(function() {

jQuery.event.remove( this, types, fn, selector );

});

},

bind: function( types, data, fn ) {

return this.on( types, null, data, fn );

},

unbind: function( types, fn ) {

return this.off( types, null, fn );

},

live: function( types, data, fn ) {

jQuery( this.context ).on( types, this.selector, data, fn );

return this;

},

die: function( types, fn ) {

jQuery( this.context ).off( types, this.selector || "**", fn );

return this;

},

delegate: function( selector, types, data, fn ) {

return this.on( types, selector, data, fn );

},

undelegate: function( selector, types, fn ) {

// ( namespace ) or ( selector, types [, fn] )

return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );

},

trigger: function( type, data ) {

return this.each(function() {

jQuery.event.trigger( type, data, this );

});

},

triggerHandler: function( type, data ) {

if ( this[0] ) {

return jQuery.event.trigger( type, data, this[0], true );

}

},

toggle: function( fn ) {

// Save reference to arguments for access in closure

var args = arguments,

guid = fn.guid || jQuery.guid++,

i = 0,

toggler = function( event ) {

// Figure out which function to execute

var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;

jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );

// Make sure that clicks stop

event.preventDefault();

// and execute the function

return args[ lastToggle ].apply( this, arguments ) || false;

};

// link all the functions, so any of them can unbind this click handler

toggler.guid = guid;

while ( i < args.length ) {

args[ i++ ].guid = guid;

}

return this.click( toggler );

},

hover: function( fnOver, fnOut ) {

return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );

}

});

jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +

"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +

"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {

// Handle event binding

jQuery.fn[ name ] = function( data, fn ) {

if ( fn == null ) {

fn = data;

data = null;

}

return arguments.length > 0 ?

this.on( name, null, data, fn ) :

this.trigger( name );

};

if ( jQuery.attrFn ) {

jQuery.attrFn[ name ] = true;

}

if ( rkeyEvent.test( name ) ) {

jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;

}

if ( rmouseEvent.test( name ) ) {

jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;

}

});

}

11、总结

最后,我们修改jquery.main.js文件,调用以上各类初始化代码。

// 整体结构

(function(window,undefined){

var jQuery = (function(){

var jQuery = function(selector, context){

// 调用init方法创建jQuery对象

return new jQuery.prototype.init(selector, context,rootjQuery);

};

// 临时变量

var _$ = window.$;

var _jQuery = window.jQuery;

var rootjQuery;

var toString = Object.prototype.toString;

// 初始化jQuery对象

jQuery_init(jQuery);

jQuery_extend_defined(jQuery);

jQuery_extend_core(jQuery,_$,_jQuery,toString);

// All jQuery objects should point back to these

rootjQuery = jQuery(document);

return jQuery;

})();

// 初始化jQuery各个模块

jQuery_Sizzle(jQuery);

jQuery_extend_sizzle(jQuery);

jQuery_support(jQuery);

jQuery_extend_attributes(jQuery);

jQuery_extend_dom(jQuery);

jQuery_extend_event(jQuery);

window.$ = window.jQuery = jQuery;

})(window);

修改测试文件,依次引入各文件进行测试。

<!doctype html>

<html lang="en">

<head>

<meta charset="UTF-8">

<script src="jquery.init.js"></script>

<script src="jquery.extend.define.js"></script>

<script src="jquery.extend.core.js"></script>

<script src="jquery.sizzle.js"></script>

<script src="jquery.extend.sizzle.js"></script>

<script src="jquery.extend.support.js"></script>

<script src="jquery.extend.attrs.js"></script>

<script src="jquery.extend.dom.js"></script>

<script src="jquery.extend.event.js"></script>

<script src="jquery.main.js"></script>

<title>jquery demo</title>

</head>

<body>

<div id=‘tt‘>我是一个div</div>

<script>

var s = $("#tt").text();

alert(s);

$("#tt").text("我更新了div的文本");

</script>

</body>

</html>

时间: 2024-08-07 08:56:14

第五节:JQuery框架源码简析(3)的相关文章

第五节:JQuery框架源码简析(1)

(转自老惠的博客) JQuery是一个应用广泛.非常优秀的JavaScript框架,其代码简洁而优雅,有很多值得我们学习的地方.这里仅仅对其代码结构做一个简单的分析,方便大家的理解和学习. 我们进行分析.分解的基准版本是jQuery1.7.1. 开始之前,请准备好以下素材和工具: jQuery源代码:jquery-1.7.1.js 文本编辑器:EditPlus,或者你喜欢的 参考书:<jQuery高级编程>.<jQuery技术内幕:深入解析jQuery架构设计与实现原理>.<

第五节:JQuery框架源码简析(2)

(续1) 5.选择器Sizzle 我们把选择器Sizzle实现的代码放在文件jquery.sizzle.js中.关于选择器Sizzle的说明,请看<jQuery技术内幕:深入解析jQuery架构设计与实现原理>,这里不再赘述了. /*! * Sizzle CSS Selector Engine *  Copyright 2011, The Dojo Foundation *  Released under the MIT, BSD, and GPL Licenses. *  More info

SpringMVC学习——概念、流程图、源码简析(一)

学习资料:开涛的<跟我学SpringMVC.pdf> 众所周知,springMVC是比较常用的web框架,通常整合spring使用.这里抛开spring,单纯的对springMVC做一下总结. 概念 HandlerMapping:处理器映射,对请求的URL进行映射为具体的处理器(如果有拦截器也包含拦截器,会将Handler和多个HandlerInterceptor封装为HandlerExecutionChain对象) HandlerAdapter:处理器适配器,适配不同类型的处理器,如Cont

并发工具-CyclicBarrier源码简析

CyclicBarrier是循环栅栏的意思,循环的等待多个线程执行任务: <1> 示例代码如下: public class CyclicBarrierTest { public static CyclicBarrier cb = new CyclicBarrier(3, () -> System.out.println("-------开始点名-------")); public static void main(String[] args) { System.out

JDK源码简析--java.lang包中的基础类库

题记 JDK,Java Development Kit. 我们必须先认识到,JDK只是,仅仅是一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含量来说,还是在一个层级上,它们都是需要被编译成字节码,在JRE中运行的,JDK编译后的结果就是jre/lib下得rt.jar,我们学习使用它的目的是加深对Java的理解,提高我们的Java编码水平. 本系列所有文章基于的JDK版本都是1.7.16. 本节内容 在本节中,简析java.lang包所包

JDK源码简析--java.util包中的工具类库

题记 JDK,Java Development Kit. 我们必须先认识到,JDK只是,仅仅是一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含量来说,还是在一个层级上,它们都是需要被编译成字节码,在JRE中运行的,JDK编译后的结果就是jre/lib下得rt.jar,我们学习使用它的目的是加深对Java的理解,提高我们的Java编码水平. 本系列所有文章基于的JDK版本都是1.7.16. 本节内容 在本节中,简析java.util包所包

0002 - Spring MVC 拦截器源码简析:拦截器加载与执行

1.概述 Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理.例如通过拦截器可以进行权限验证.记录请求信息的日志.判断用户是否登录等. 2.简单示例 2.1.继承 HandlerInterceptorAdapter 抽象类实现一个拦截器.代码如下: public class DemoInterceptor extends HandlerInterceptorAdapter { @Override    pu

[tomcat]源码简析 异步/非阻塞和请求构成

提出疑惑 SpringFramework5.0又新增加了一个功能Webflux(响应式编程),是一个典型非阻塞异步的框架.我们知道servlet3.0实现异步(AsyncContext),servlet3.1又提出了非阻塞IO.对此我一直有两点疑惑:1.tomcat8底层已经默认使用NIO了,不是已经是IO非阻塞了吗,怎么又说servlet3.1解决了非阻塞.2.关于异步,如果开发者在serlvet中开一个业务线程来实现,也算异步,为什么3.0还提供了一个组件来解决,那么这种方式和开发者自己开个

Linux Hugetlbfs内核源码简析-----(一)Hugetlbfs初始化

一.引言 为了实现虚拟内存管理机制,操作系统对内存实行分页管理.自内存“分页机制”提出之始,内存页面的默认大小便被设置为 4096 字节(4KB),虽然原则上内存页面大小是可配置的,但绝大多数的操作系统实现中仍然采用默认的 4KB 页面.当某些应用的需要使用的内存达到几G.甚至几十G的时候,4KB的内存页面将严重制约程序的性能. CPU缓存中有一组缓存专门用于缓存TLB,但其大小是有限的.当采用的默认页面大小为 4KB,其产生的TLB较大,因而将会产生较多 TLB Miss 和缺页中断,从而大大