Author: nuysoft/Gao Yun QQ: 47214707 EMail: nuysoft@gmail.com
Statement: This article is an original article. If you need to reprint, please indicate the source and retain the original link.
Read, read, write and write. Please tell me if something is wrong. Let’s communicate more and make progress together. The PDF of this chapter will be released when this chapter is finished.
For the directory of the jQuery source code analysis series, please check http://nuysoft.iteye.com/blog/1177451. If I want to write it systematically, I will start with the parts that interest me. If you are interested in which module If you recommend giving priority to analysis, you can tell me and we can study together.
3.4 Other static tool functions
// Extend utility function
jQuery.extend({
// Release jQuery control of $
// Many JavaScript libraries use $ as function or variable names, and jQuery does the same.
// In jQuery, $ is just an alias for jQuery, so all functionality is guaranteed even without using $.
// If we need to use another JavaScript library besides jQuery, we can call it. $.noConflict() returns control to the library.
// By passing the parameter true to this method, we can return control of both $ and jQuery to another JavaScript library.
noConflict: function( deep ) {
// Hand over control of $
if ( window.$ === jQuery ) {
window.$ = _$;
}
// Hand over jQuery Control
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
},
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,
// A counter to track how many items to wait for before
// the ready event fires. See #6781
// A counter used to track the number of times to wait before the ready event is triggered
readyWait: 1,
// Hold (or release) the ready event
// Continue to wait or trigger
holdReady : function( hold ) {
if ( hold ) {
jQuery.readyWait ;
} else {
jQuery.ready( true );
}
},
/ / Handle when the DOM is ready
// Handle when the document is loaded
ready: function( wait ) {
// Either a released hold or an DOMready/load event and not yet ready
//
if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
// Make sure document.body exists
if ( !document.body ) {
return setTimeout( jQuery.ready, 1 );
}
// Remember that the DOM is ready
jQuery.isReady = true;
// If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
}
// If there are functions bound, to execute
readyList.resolveWith( document, [ jQuery ] );
/ / Trigger any bound ready events
if ( jQuery.fn.trigger ) {
jQuery( document ).trigger( "ready" ).unbind( "ready" );
}
}
},
//Initialize the readyList event processing function queue
// Compatible with the differences in binding events between different browsers
bindReady: function() {
if ( readyList ) {
return;
}
readyList = jQuery._Deferred();
// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
return setTimeout( jQuery.ready, 1 );
}
// Mozilla, Opera and webkit nightlies currently support this event
// Compatible events, by detecting the browser's functional features instead of sniffing the browser
if ( document.addEventListener ) {
// Use the handy event callback
// Use a faster loading event
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
/ / Register window.onload callback function
window.addEventListener( "load", jQuery.ready, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
// Ensure onreadystatechange is triggered before onload, which may be slower but safer for iframes
document.attachEvent( "onreadystatechange" , DOMContentLoaded );
// A fallback to window.onload, that will always work
// Register window.onload callback function
window.attachEvent( "onload", jQuery.ready );
// If IE and not a frame
//continuously check to see if the document is ready
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e) {}
if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
},
// See test/unit /core.js for details concerning isFunction.
// Since version 1.3, DOM methods and functions like alert
// aren't supported. They return false on IE (#2968).
// Whether Function
isFunction: function( obj) {
return jQuery.type(obj) === "function";
},
// Whether it is an array
// If the browser has built-in To implement Array.isArray, use the browser's own implementation.
// Otherwise, convert the object to String to see if it is "[object Array]".
isArray: Array.isArray || function( obj ) {
return jQuery.type(obj) === "array";
},
// A crude way of determining if an object is a window
// Simple judgment (judging the setInterval attribute) whether the window object
isWindow: function( obj ) {
return obj && typeof obj === "object" && "setInterval" in obj;
},
// Whether it is a reserved word NaN
isNaN: function( obj ) {
// Equal to null or not a number or call window.isNaN to judge
return obj == null | | !rdigit.test( obj ) || isNaN( obj );
},
// Get the type of object
type: function( obj ) {
// Create an object through the core API , no new keyword is needed
// Ordinary functions will not work
// Call the Object.prototype.toString method to generate a string in the "[object Xxx]" format
// class2type[ "[object " name "]" ] = name.toLowerCase();
return obj == null ?
String( obj ) :
class2type[ toString.call(obj) ] || "object";
} ,
// Check whether obj is a pure object (object created through "{}" or "new Object")
// console.info( $.isPlainObject( {} ) ); // true
// console.info( $.isPlainObject( '' ) ); // false
// console.info( $.isPlainObject( document.location ) ); // true
// console. info( $.isPlainObject( document ) ); // false
// console.info( $.isPlainObject( new Date() ) ); // false
// console.info( $.isPlainObject( ) ); // false
// isPlainObject analysis and reconstruction http://www.jb51.net/article/25047.htm
// Understanding jQuery.isPlainObject() http://www.cnblogs .com/phpmix/articles/1733599.html
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 well
// Must be an object
// Because an illegal pointer exception will be thrown in IE8, the constructor must be checked Attribute
//DOM node and window object, return false
// obj does not exist or is of non-object type or DOM node or widnow object, directly return false
// Test the following three possible situations:
// jQuery.type(obj) !== "object" type is not object, ignore it
// obj.nodeType thinks that DOM node is not a pure object
// jQuery.isWindow(obj) thinks that window is not a pure object Object
if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
return false;
}
// Not own constructor property must be Object
// Test constructor property
// It has a constructor function constructor, but it is not its own property (that is, inherited through prototype),
if ( obj.constructor &&
!hasOwn.call(obj, "constructor") &&
!hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
return false;
}
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var key;
for ( key in obj ) {}
// key === undefined and does not have any attributes, it is considered a simple pure object
// hasOwn.call( obj, key ) The attribute key is not empty, and the object of the attribute key is its own (that is, it is not inherited through prototype)
return key === undefined || hasOwn.call( obj, key );
},
// Whether the object is empty
isEmptyObject: function( obj ) {
for ( var name in obj ) {
return false;
}
return true;
},
// Throw an exception
error: function( msg ) {
throw msg;
},
// Parse JSON
// parseJSON turns a string into a JSON object.
// We generally use eval. parseJSON encapsulates this operation, but eval is used as a last resort.
// Because JSON serialization and deserialization APIs have been added to the latest JavaScript standard.
// If the browser supports this standard, these two APIs are implemented in the JS engine using Native Code, and the efficiency is definitely much higher than eval.
// At present, both Chrome and Firefox4 support this API.
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 first
// Native JSON API. Deserialization is JSON.stringify(object)
if ( 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.js
// ... Check the string validity roughly
if ( rvalidchars.test( data.replace( rvalidescape, "@" )
.replace( rvalidtokens, "]" )
.replace( rvalidbraces, "")) ) {
return (new Function( "return " data )) ();
}
jQuery.error( "Invalid JSON: " data );
},
// Cross-browser xml parsing
// (xml & tmp used internally)
// Parse XML cross-browser
// The parseXML function is also mainly a package of standard API and IE.
//The standard API is the DOMParser object.
// IE uses the ActiveXObject object of Microsoft.XMLDOM.
parseXML: function( data , xml , tmp ) {
if ( window.DOMParser ) { // Standard standard XML parser
tmp = new DOMParser();
xml = tmp.parseFromString( data , "text/xml" );
} else { // IE IE's XML parser
xml = new ActiveXObject( "Microsoft.XMLDOM" );
xml.async = "false";
xml.loadXML( data );
}
tmp = xml.documentElement;
if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) {
jQuery.error( "Invalid XML: " data );
}
return xml;
},
// No-op function
noop: function() {},
// Evaluates a script in a global context
// Workarounds based on findings by Jim Driscoll
// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval- javascript-global-context
// The globalEval function loads a script into the global context (window).
// window.execScript can be used in IE.
// Other browsers need to use eval.
// Because the entire jQuery code is an entire anonymous function, the current context is jQuery. If you want to set the context to window, you need to use globalEval.
globalEval: function( data ) {
// data is not empty
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 );
}
},
// Determine whether the node names are the same
nodeName: function( elem, name ) {
// Ignore case
return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
},
// args is for internal usage only
// Traverse objects or arrays
each: function( object, callback, args ) {
var name, i = 0,
length = object.length,
isObj = length === undefined || jQuery.isFunction( object );
// If there are parameters args, call apply, the context is set to the currently traversed object, and the parameters are args
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
// If there is no parameter args, call is called, the context is set to the currently traversed object, the parameters are set to key/index and value
} 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;
},
// Use native String.trim function wherever possible
// Use the local String.trim method as much as possible, otherwise filter the leading spaces first, and then filter the trailing spaces
trim: trim ?
function( text ) {
return text == null ?
"" :
trim.call( text );
} :
// Otherwise use our own trimming functionality
function( text ) {
return text == null ?
"" :
text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
},
// results is for internal usage only
// Convert pseudo array to array
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)
// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
// A lot of browser compatibility tests, really painful
var type = jQuery.type( array );
// Test: Is there a length attribute, string, function, Regular
// is not an array, not even a pseudo-array
if ( array.length == null
|| type === "string"
|| type === "function"
|| type === "regexp"
|| jQuery.isWindow( array ) ) {
push.call( ret, array );
} else {
// $.type ( $('div') ) // object
jQuery.merge( ret, array );
}
}
return ret;
},
//
inArray: function( elem, array ) {
// Is there a localized Array.prototype.indexOf
if ( indexOf ) {
// Directly call Array.prototype.indexOf
return indexOf. call(array, elem);
}
// Traverse the array, find if there are exactly equal elements, and return the subscript
// Tips for looping: store array.length in the length variable , you can reduce one scope search
for ( var i = 0, length = array.length; i < length; i ) {
if ( array[ i ] === elem ) {
return i;
}
}
// If -1 is returned, it means it is not in the array
return -1;
},
// Merge array second into array first
merge: function( first, second ) {
var i = first.length, //
j = 0;
// If the length attribute of second is of type Number, treat second as an array Processing
if ( typeof second.length === "number" ) {
for ( var l = second.length; j < l; j ) {
first[ i ] = second[ j ] ;
}
} else {
// Traverse second and add non-undefined values to first
while ( second[j] !== undefined ) {
first[ i ] = second[ j ];
}
}
// Correct the length attribute of first, because first may not be a real array
first.length = i;
return first;
},
// Filter the array and return a new array; retain it when callback returns true; if inv is true, it will be retained only when callback returns false
grep: function( elems, callback, inv ) {
var ret = [], retVal;
inv = !!inv;
// Go through the array, only saving the items
// that pass the validator function
// Traverse the array, only save the items that pass Verify the elements of the function callback
for ( var i = 0, length = elems.length; i < length; i ) {
// The parameter list of the callback here is: value, index, which is consistent with the habit of each
retVal = !!callback( elems[ i ], i );
// Whether to reverse the selection
if ( inv !== retVal ) {
ret.push( elems[ i ] ) ;
}
}
return ret;
},
// arg is for internal usage only
// Convert the elements/attributes of the array or object elems into a new array
map: function( elems, callback, arg ) {
var value, key, ret = [],
i = 0,
length = elems.length,
// jquery objects are treated as arrays
// Detect whether elems are (pseudo) arrays
// 1. Treat the jQuery object as an array
// 2. Check whether the length attribute exists, length is equal to 0, or whether the first and last elements exist, or jQuery.isArray returns true
isArray = elems instanceof jQuery
|| length !== undefined && typeof length === "number"
&& ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
// It’s the difference between an array or an object, it’s just the way of traversing, there is no other difference
// Go through the array, translating each of the items to their
// Traverse the array, call callback on each element, and store the return value that is not null into ret
if ( isArray ) {
for ( ; i < length; i ) {
// Execute callback, the parameters are value, index, arg in order
value = callback( elems[ i ], i, arg );
// If null is returned, ignore (no return The value function will return undefined)
if ( value != null ) {
ret[ ret.length ] = value;
}
}
// Go through every key on the object ,
// Traverse the object, call callback for each attribute, store the return value that is not null into ret
} else {
for ( key in elems ) {
// Execute callback, the parameters are value, key, arg in order
value = callback( elems[ key ], key, arg );
// Same as above
if ( value != null ) {
ret[ ret .length ] = value;
}
}
}
// Flatten any nested arrays
// Flatten nested arrays
// concat:
// If an item is an array, add its contents to the end.
// If the item is not an array, add it to the end of the array as a single array element.
return ret.concat.apply( [], ret );
},
// A global GUID counter for objects
guid: 1,
// Bind a function to a context , optionally partially applying any
// arguments.
// Proxy method: specify context for fn (i.e. this)
// jQuery.proxy( function, context)
// jQuery.proxy( context, name )
proxy: function( fn, context ) {
// If context is a string, set the context to fn, and fn is fn[ context ]
// That is, set the context method of fn The context is fn (isn’t this the default???TODO)
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.
// Quick check to determine if target is callable, in the spec In the description, a TypeError will be thrown,
// But here only returns undefined
if ( !jQuery.isFunction( fn ) ) {
return undefined;
}
// Simulated bind
var args = slice.call( arguments, 2 ), // Remove fn,context from the parameter list
proxy = function() {
// Set context to context and parameters
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 removed
/ / Unify guid so that proxy can be removed
proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid ;
return proxy;
},
/ / Mutifunctional method to get and set values to a collection
// The value/s can be optionally executed if its a function
// Multifunctional function, read or set the attribute value of the collection; the value is a function will be executed when
// fn: jQuery.fn.css, jQuery.fn.attr, jQuery.fn.prop
access: function( elems, key, value, exec, fn, pass ) {
var length = elems.length;
// Setting many attributes
// If there are multiple attributes, iterate
if ( typeof key === "object" ) {
for ( var k in key ) {
jQuery.access( elems, k, key[k], exec, fn, value );
}
return elems;
}
// Setting one attribute
// Set only one property
if ( value !== undefined ) {
// Optionally, function values get executed if exec is true
exec = !pass && exec && jQuery.isFunction( value);
for ( var i = 0; i < length; i ) {
fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[ i], key ) ) : value, pass );
}
return elems;
}
// Getting an attribute
// Reading attribute
return length ? fn( elems[0], key ) : undefined;
},
// Convenient function to get the current time
now: function() {
return (new Date()).getTime();
},
// Use of jQuery.browser is frowned upon.
// More details: http://docs.jquery.com/Utilities/jQuery.browser
// Use is deprecated jQuery.browser, it is recommended to use jQuery.support
// Navigator Information about the browser being used
// Navigator.userAgent A read-only string that declares the value of the user agent header used by the browser for HTTP requests
uaMatch: function( ua ) {
ua = ua.toLowerCase();
// Match each browser in turn
var match = rwebkit.exec( ua ) ||
ropera. exec( ua ) ||
rmsie.exec( ua ) ||
ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
[];
/ / match[1] || ""
// When match[1] is false (empty string, null, undefined, 0, etc.), the default is ""
// match[2] || " 0"
// When match[2] is false (empty string, null, undefined, 0, etc.), the default is "0"
return { browser: match[1] || "", version: match[2] || "0" };
},
// Create a new copy of jQuery. The properties and methods of the copy can be changed, but the original jQuery object will not be affected
// There are two usages:
// 1. Override jQuery methods without destroying the original methods
// 2. Encapsulate to avoid namespace conflicts and can be used to develop jQuery plug-ins
// Worth noting What's more, the jQuery.sub() function does not provide real isolation. All properties and methods still point to the original jQuery
// If you use this method to develop plug-ins, it is recommended to give priority to the jQuery UI widget project
sub : function() {
function jQuerySub( selector, context ) {
return new jQuerySub.fn.init( selector, context );
}
jQuery.extend( true, jQuerySub, this ); // Deep copy, copy all properties and methods of jQuery to jQuerySub
jQuerySub.superclass = this;
jQuerySub.fn = jQuerySub.prototype = this(); //
jQuerySub.fn.constructor = jQuerySub;
jQuerySub.sub = this.sub;
jQuerySub.fn.init = function init( selector, context ) {
if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
context = jQuerySub( context );
}
return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
};
jQuerySub.fn.init.prototype = jQuerySub.fn;
var rootjQuerySub = jQuerySub(document);
return jQuerySub;
},
// Browser type and version:
// $.browser.msie/mozilla/ webkit/opera
// $.browser.version
// It is not recommended to sniff the browser type jQuery.browser, but check the browser's functional features jQuery.support
// In the future jQuery.browser may Will be moved to a plug-in
browser: {}
});