源码355~905行,这一节的源码部分比较长,不会对所有的代码进行分析
这部分主要有:ready文档加载,数据类型判断,数据解析,数组操作等函数
接下来看源码,部分需要讲的函数分开详细介绍,这节的内容多,但这块的内容后面的扩展和UI都经常用到:
jQuery.extend({
//默认情况下jquery支持jQuery和$的引用方式,但考虑到很多JS框架都用$,避免在使用jquery框架时使用$和其他框架定义冲突,所以增加noConflict方法注销$操作在jquery中的使用
noConflict: function( deep ) {},
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,//DOM是否加载完成
// A counter to track how many items to wait for before
// the ready event fires. See #6781
readyWait: 1,
// Hold (or release) the ready event
holdReady: function( hold ) {},//暂停或恢复.ready() 事件的执行。
// Handle when the DOM is ready
ready: function( wait ) {},//下面细讲
// 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).
isFunction: function( obj ) {},//类型是否为function
isArray: Array.isArray || function( obj ) {},//是否为数组
isWindow: function( obj ) {},//是否为window对象
isNumeric: function( obj ) {},//数字
type: function( obj ) {},//基础类型
isPlainObject: function( obj ) {},//是否为纯粹对象(通过 "{}" 或者 "new Object" 创建的),如JSON对象或函数对象
isEmptyObject: function( obj ) {},//空对象
error: function( msg ) {},//抛出异常信息msg
// data: string of html
// context (optional): If specified, the fragment will be created in this context, defaults to document
// scripts (optional): If true, will include scripts passed in the html string
parseHTML: function( data, context, scripts ) {},//下面细讲
parseJSON: function( data ) {},//把JSON字符串解析为json对象
// Cross-browser xml parsing
parseXML: function( data ) {},//把xml字符串解析为XML对象
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
globalEval: function( data ) {},//在全局范围下执行一些JavaScript eval操作,这和普通的eval的区别是其所在的作用域
// Convert dashed to camelCase; used by the css and data modules
// Microsoft forgot to hump their vendor prefix (#9572)
camelCase: function( string ) {},
nodeName: function( elem, name ) {},//判断elem的nodeName属性值是否和传入的name值一致
// args is for internal usage only
each: function( obj, callback, args ) {},//下面细讲
// Use native String.trim function wherever possible
trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
function( text ) {
return text == null ?
"" :
core_trim.call( text );
} :
// Otherwise use our own trimming functionality
function( text ) {
return text == null ?
"" :
( text + "" ).replace( rtrim, "" );
},
// results is for internal usage only
makeArray: function( arr, results ) {},//把一个非数组或数字类型的对象转换为数组返回,并对arr和results进行合并
inArray: function( elem, arr, i ) {},//判断arr[i]的值是否为elem,没找到返回-1,否则返回i
merge: function( first, second ) {},//合并数组,把second合并到first
grep: function( elems, callback, inv ) {},//按callback返回值和inv之间的关系从elems中帅选数据
// arg is for internal usage only
map: function( elems, callback, arg ) {},//把elems数组/对象中的每一项进行callback(elems[ i ], i, arg)或callback( elems[ key ], key, arg )操作后的值从新组成新的数组返回
// A global GUID counter for objects
guid: 1,
// Bind a function to a context, optionally partially applying any
// arguments.
proxy: function( fn, context ) {},//下面细讲
// Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function
access: function( elems, fn, key, value, chainable, emptyGet, pass ) {},//下面细讲
now: function() {}//返回当前时间的毫秒表示
});
// Populate the class2type map
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
});
1.jQuery.ready(func),当DOM加载完后执行func函数,支持jQuery.ready(true)方式
// Handle when the DOM is ready
ready: function( wait ) {
//$.ready(true),该处针对的是holdReady的应用,对ready时间的挂起和释放
// Abort if there are pending holds or we're already ready
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
return;
}
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
//检查document.body加载情况,如果未完成继续等待1毫秒
if ( !document.body ) {
return setTimeout( jQuery.ready, 1 );
}
// Remember that the DOM is ready
//到此处说明DOM已经处于加载完成状态,并更新isReady 的值
jQuery.isReady = true;
// If a normal DOM Ready event fired, decrement, and wait if need be
//holdReady的等待未完全释放
if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
}
// If there are functions bound, to execute 执行绑定事件
//参见后面deferred.resolveWith的讲解,
readyList.resolveWith( document, [ jQuery ] );
// Trigger any bound ready events
//触发ready事件
if ( jQuery.fn.trigger ) {
jQuery( document ).trigger("ready").off("ready");
}
}
2.jQuery.parseHTML(data, context, scripts),HTML解析函数:
data为html字符串
context为表示html被创建的上下文,如果未指定默认为document
scripts是否包含scripts
// data: string of html
// context (optional): If specified, the fragment will be created in this context, defaults to document
// scripts (optional): If true, will include scripts passed in the html string
parseHTML: function( data, context, scripts ) {
var parsed;
if ( !data || typeof data !== "string" ) {//parseHTML只解析非空字符串
return null;
}
//context 为boolean
if ( typeof context === "boolean" ) {
scripts = context;
context = 0;
}
//设置context 的值
context = context || document;
// Single tag 匹配 <a>...</a> 格式
if ( (parsed = rsingleTag.exec( data )) ) {
return [ context.createElement( parsed[1] ) ];//创建节点
}
//jQuery.buildFragment 参见6122~6161行,后面章节再讲这个内容,该方法返回一个包含文本片段的JSON对象,返回信息包含是否缓存片段
parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] );
return jQuery.merge( [],
(parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes );
}
3.jQuery.each(obj, callback, args),函数和数组迭代器:
obj:函数/数组
callback:回调函数
args:添加给callback的回调函数
each: function( obj, callback, args ) {
var name,
i = 0,
length = obj.length,
isObj = length === undefined || jQuery.isFunction( obj );
if ( args ) {//args 为非空
if ( isObj ) {//为函数
for ( name in obj ) {//在传递参数的情况下,在当前函数obj[ name ]作用下,运行callback(args )的调用
if ( callback.apply( obj[ name ], args ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.apply( obj[ i++ ], args ) === false ) {//和对象不同的只是作用域的引用形式
break;
}
}
}
// A special, fast, case for the most common use of each
//在args未传递的情况下,当前回调函数的参数就为obj中的key和value,作用域不变。
} else {
if ( isObj ) {
for ( name in obj ) {
if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) {
break;
}
}
}
}
return obj;
}
//这里需要清楚apply和call的区别和作用:1。每个函数都包含两个非继承而来的方法:apply()和call()。2。他们的用途相同,都是在特定的作用域中调用函数。3。接收参数方面不同,apply()接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
4。call()方法第一个参数与apply()方法相同,但传递给函数的参数必须列举出来。
4.jQuery.each( fn, context ),修改fn的上下文作用域为context :
// Bind a function to a context, optionally partially applying any
// arguments.
proxy: function( fn, context ) {
var tmp, args, proxy;
//匹配JSON格式的函数,var test = {'a':1,'d'=42,'fn':function(){}}
//proxy(test,'fn')
if ( typeof context === "string" ) {
tmp = fn[ context ];
context = fn;
fn = tmp;
}
// Quick check to determine if target is callable, in the spec
// this throws a TypeError, but we will just return undefined.
if ( !jQuery.isFunction( fn ) ) {//校验fn类型
return undefined;
}
// Simulated bind
//
args = core_slice.call( arguments, 2 );//支持俩个以上的参数传递
//设置fn的上下文及其他参数,并生成proxy函数
proxy = function() {
return fn.apply( context, args.concat( core_slice.call( arguments ) ) );
};
// Set the guid of unique handler to the same of original handler, so it can be removed
proxy.guid = fn.guid = fn.guid || jQuery.guid++;
//返回函数
return proxy;
}
4.jQuery.access( elems, fn, key, value, chainable, emptyGet, pass ),多功能方法,读取或设置集合的属性值,如果值为function时会被执行
// Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function
access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
var exec,
bulk = key == null,
i = 0,
length = elems.length;
// Sets many values
if ( key && typeof key === "object" ) {
//针对key为多集合对象,则迭代调用自身
for ( i in key ) {
jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
}
chainable = 1;
// Sets one value 单一值
} else if ( value !== undefined ) {
// Optionally, function values get executed if exec is true
exec = pass === undefined && jQuery.isFunction( value );
if ( bulk ) {
// Bulk operations only iterate when executing function values
if ( exec ) {
exec = fn;
fn = function( elem, key, value ) {
return exec.call( jQuery( elem ), value );
};
// Otherwise they run against the entire set
} else {
fn.call( elems, value );
fn = null;
}
}
if ( fn ) {
for (; i < length; i++ ) {
fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
}
}
chainable = 1;
}
return chainable ?
elems :
// Gets
bulk ?
fn.call( elems ) :
length ? fn( elems[0], key ) : emptyGet;
}