https://github.com/jquery/jquery
Cube -
Page -
Concave -
Zoom -
Linear -
None -
Default
Sky -
Beige -
Simple -
Serif -
Night -
Default
(function( window, undefined ) {
// 构造jQuery对象
var jQuery = (function() {
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
}
return jQuery;
})();
// 工具函数 Utilities
// 回调函数对象 Callbacks Object
// 异步队列对象 Deferred Object
// 浏览器测试 Support
// 数据缓存 Data
// 队列 Queue
// 属性操作 Attributes
// 事件处理 Events
// 选择器 Sizzle
// DOM遍历 Traversing
// DOM操作 Manipulation
// 样式操作 CSS
// 异步请求 AJAX
// 动画 Effects
// 坐标 Offset 和 大小 Dimensions
window.jQuery = window.$ = jQuery;
})(window);
(function( window, undefined ) {
// jQuery的所有代码
})(window);
16 (function( window, undefined ) {
// 构造 jQuery 对象
22 var jQuery = (function() {
25 var jQuery = function( selector, context ) {
27 return new jQuery.fn.init( selector, context, rootjQuery );
28 },
// 一堆局部变量声明
97 jQuery.fn = jQuery.prototype = {
98 constructor: jQuery,
99 init: function( selector, context, rootjQuery ) { ... },
// 一堆原型属性和方法
319 };
322 jQuery.fn.init.prototype = jQuery.fn;
324 jQuery.extend = jQuery.fn.extend = function() { ... };
388 jQuery.extend({
// 一堆静态属性和方法
892 });
955 return jQuery;
957 })();
// 省略其他模块的代码 ...
9246 window.jQuery = window.$ = jQuery;
9266 })( window );
为什么要在调用构造函数 jQuery() 内部用运算符 new 创建并返回另一个构造函数的实例?
为什么在第97行执行 jQuery.fn = jQuery.prototype,设置 jQuery.fn 指向构造函数 jQuery() 的原型对象 jQuery.prototype?
既然调用构造函数 jQuery() 返回的 jQuery 对象实际上是构造函数 jQuery.fn.init() 的实例,为什么能在构造函数 jQuery.fn.init() 的实例上调用构造函数 jQuery() 的原型方法和属性,例如: $('#id').length 和 $('#id').size()?
为什么要把第25~955行的代码包裹在一个自调用匿名函数中,然后把第25行定义的构造函数 jQuery() 作为返回值赋值给为第22行的 jQuery 变量?去掉这个自调用匿名函数,直接在第25行定义构造函数 jQuery() 不也可以吗?去掉了不是更容易阅读和理解吗?
为什么要覆盖构造函数 jQuery() 的原型对象 jQuery.prototype?
97 jQuery.fn = jQuery.prototype = {
98 constructor: jQuery,
99 init: function( selector, context, rootjQuery ) {}
210 selector: "",
213 jquery: "1.7.1",
216 length: 0,
219 size: function() {},
223 toArray: function() {},
229 get: function( num ) {},
241 pushStack: function( elems, name, selector ) {},
270 each: function( callback, args ) {},
274 ready: function( fn ) {}, //
284 eq: function( i ) {},
291 first: function() {},
295 last: function() {},
299 slice: function() {},
304 map: function( callback ) {},
310 end: function() {},
316 push: push,
317 sort: [].sort,
318 splice: [].splice
319 };
388 jQuery.extend({
389 noConflict: function( deep ) {},
402 isReady: false,
406 readyWait: 1,
409 holdReady: function( hold ) {},
418 ready: function( wait ) {},
444 bindReady: function() {},
492 isFunction: function( obj ) {},
496 isArray: Array.isArray || function( obj ) {},
501 isWindow: function( obj ) {},
505 isNumeric: function( obj ) {},
509 type: function( obj ) {},
515 isPlainObject: function( obj ) {},
544 isEmptyObject: function( obj ) {},
551 error: function( msg ) {},
555 parseJSON: function( data ) {},
581 parseXML: function( data ) {},
601 noop: function() {},
606 globalEval: function( data ) {},
619 camelCase: function( string ) {},
623 nodeName: function( elem, name ) {},
628 each: function( object, callback, args ) {},
669 trim: trim ? function( text ) {} : function( text ) {},
684 makeArray: function( array, results ) {},
702 inArray: function( elem, array, i ) {},
724 merge: function( first, second ) {},
744 grep: function( elems, callback, inv ) {},
761 map: function( elems, callback, arg ) {},
794 guid: 1,
798 proxy: function( fn, context ) {},
825 access: function( elems, key, value, exec, fn, pass ) {},
852 now: function() {},
858 uaMatch: function( ua ) {},
870 sub: function() {},
891 browser: {}
892 });
$.ajax({
url: 'ajax/test.html',
success: function(data, status, xhr) { ... },
error: function(xhr, status, errMsg) { ... },
complete: function(xhr, status) { ... }
});
$.ajax( 'ajax/test.html' )
// 对应 success
.done(function(data, textStatus, jqXHR) { ... })
.done(function(data, textStatus, jqXHR) { ... })
// 对应 error
.fail(function(jqXHR, textStatus, errorThrown) { ... })
.fail(function(jqXHR, textStatus, errorThrown) { ... })
// 对应 complete
.complete(function(jqXHR, statusText){ ... })
.complete(function(jqXHR, statusText){ ... });
996 jQuery.Callbacks = function( flags ) {
1181 };
1189 jQuery.extend({
1191 Deferred: function( func ) {
1282 },
1285 when: function( firstParam ) {
1325 }
1326 });
返回一个多功能链式对象,提供强大的回调函数列表管理功能,支持添加、移除、触发、锁定、禁用回调函数,为 jQuery.ajax()、jQuery.Deferred() 和 ready 事件提供基础功能,也可以基于它编写新的组件。
返回的多功能对象称为为“回调函数列表 Callbacks Object”,代码中用 callbacks 表示。
内部通过一个数组保存回调函数,其他方法则围绕这个数组进行操作和检测。
// 工具函数,将字符串格式的标记转换为对象格式
function createFlags( flags ) { ... }
jQuery.Callbacks = function( flags ) {
// 解析字符串标记 flags 为对象
flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
// 声明局部变量,通过闭包机制引用
var list = [], // 存放回调函数的数组
stack = [], // 在可重复触发、正在执行的列表上,重复触发时,将上下文和参数放入数组 stack 中
memory, // memory 的可能值和用途有些复杂,在分析工具方法 fire( context, args ) 时详细分析
firing, // 是否正在执行中
firingStart, // 执行回调函数时的起始下标
firingLength, // 执行回调函数时的结束下标
firingIndex, // 正在执行的回调函数的下标
add = function( args ) { ... }, // 实际添加回调函数的工具函数
fire = function( context, args ) { ... }, // 实际触发回调函数的工具函数
// 回调函数列表,方法 jQuery.Callbacks( flags ) 的返回值
self = {
add: function() {}, // 添加回调函数
remove: function() { ... }, // 移除回调函数
has: function( fn ) { ...}, // 回调函数是否在列表中
empty: function() { ... }, // 清空列表
disable: function() { ... }, // 禁用列表
disabled: function() { ... }, // 是否已禁用列表
lock: function() { ... }, // 锁定列表
locked: function() { ... }, // 是否已锁定列表
fireWith: function( context, args ) { ... }, // 使用指定的上下文和参数调用回调函数
fire: function() { ... }, // 使用指定的参数调用回调函数,上下文为 self
fired: function() { ... } // 回调函数列表是否至少执行过一次
};
return self; // 返回回调函数列表 self
};
基于 jQuery.Callbacks( flags ) 实现 ,返回一个链式工具对象,支持添加多个回调函数到回调函数列表、触发回调函数列表、传播任意同步或异步任务的成功或失败状态。
返回的链式工具对象称为“异步队列 Deferred Object”,代码中用 deferred 表示。
内部维护了三个回调函数列表:成功回调函数列表、失败回调函数列表、消息回调函数列表,其他方法则围绕这三个列表进行操作和检测。
jQuery.extend({
Deferred: function( func ) {
// 成功回调函数列表
var doneList = jQuery.Callbacks( "once memory" ),
// 失败回调函数列表
failList = jQuery.Callbacks( "once memory" ),
// 消息回调函数列表
progressList = jQuery.Callbacks( "memory" ),
// 初始状态
state = "pending",
// 异步队列的只读副本
promise = {
// done, fail, progress
// state, isResolved, isRejected
// then, always
// pipe
// promise
},
// 异步队列
deferred = promise.promise({}),
key;
// 添加触发成功、失败、消息回调函列表的方法
for ( key in lists ) {
deferred[ key ] = lists[ key ].fire;
deferred[ key + "With" ] = lists[ key ].fireWith;
}
// 添加设置状态的回调函数
deferred.done( function() {
state = "resolved";
}, failList.disable, progressList.lock )
.fail( function() {
state = "rejected";
}, doneList.disable, progressList.lock );
// 如果传入函数参数 func,则执行。
if ( func ) {
func.call( deferred, deferred );
}
// 返回异步队列 deferred
return deferred;
},
}
提供了基于一个或多个对象的状态来执行回调函数的功能,通常是基于具有异步事件的异步队列。
如果传入多个异步队列对象,方法 jQuery.when() 返回一个新的主异步队列对象的只读副本,只读副本将跟踪所传入的异步队列的最终状态。
一旦所有异步队列都变为成功状态,“主“异步队列的成功回调函数被调用;
如果其中一个异步队列变为失败状态,主异步队列的失败回调函数被调用。
/*
请求 '/when.do?method=when1' 返回 {"when":1}
请求 '/when.do?method=when2' 返回 {"when":2}
请求 '/when.do?method=when3' 返回 {"when":3}
*/
var whenDone = function(){ console.log( 'done', arguments ); },
whenFail = function(){ console.log( 'fail', arguments ); };
$.when(
$.ajax( '/when.do?method=when1', { dataType: "json" } ),
$.ajax( '/when.do?method=when2', { dataType: "json" } ),
$.ajax( '/when.do?method=when3', { dataType: "json" } )
).done( whenDone ).fail( whenFail );
对于 DOM 元素,通过分配一个唯一的关联 id 把 DOM 元素和该 DOM 元素的数据缓存对象关联起来,关联 id 被附加到以 jQuery.expando 的值命名的的属性上,数据存储在全局缓存对象 jQuery.cache 中。
读取、设置、移除数据时,通过关联 id 从全局缓存对象 jQuery.cache 中找到该 DOM 元素的数据缓存对象,然后读取或设置指定属性的值,或移除指定属性。
对于 JavaScript 对象,数据直接存储在该 JavaScript 对象的属性 jQuery.expando 上。
读取、设置、移除数据时,直接从 JavaScript 对象的数据缓存对象中,读取或设置指定属性的值,或移除指定属性。
为了避免 jQuery 内部使用的数据和用户自定义的数据发生冲突,内部数据存储在数据缓存对象上,自定义数据则存储在数据缓存对象的属性 data 上。
// 数据缓存 Data
jQuery.extend({
// 全局缓存对象
cache: {},
// 唯一 id 种子
uuid: 0,
// 页面中 jQuery 的每个副本的唯一标识
expando: ...,
// 是否有关联的数据
hasData: function( elem ) { ... },
// 设置、读取自定义数据或内部数据
data: function( elem, name, data, pvt ) { ... },
// 移除自定义数据或内部数据
removeData: function( elem, name, pvt) { ... },
// 设置、读取内部数据
_data: function( elem, name, data ) { ... },
// 是否可以设置数据
acceptData: function( elem ) { ... }
});
jQuery.fn.extend({
// 设置、读取自定义数据,解析 HTML5 属性 data-
data: function( key, value ) { ... },
// 移除自定义数据
removeData: function( key ) { ... }
});
// 解析 HTML5 属性 data-
function dataAttr( elem, key, data ) { ... }
// 检查数据缓存对象是否为空
function isEmptyDataObject( obj ) { ... }
jQuery.extend({
// 清空数据缓存对象
cleanData: function( elems ) { ... }
});
// 队列 Queue
// 检测函数队列和计数器是否完成
function handleQueueMarkDefer( elem, type, src ) { ... }
jQuery.extend({
// 计数器 type+mark 加一
_mark: function( elem, type ) { ... },
// 计数器 type+mark 减一
_unmark: function( force, elem, type ) { ... },
// 函数入队,并返回队列
queue: function( elem, type, data ) { ... },
// 函数出队,并执行
dequeue: function( elem, type ) { ... }
});
jQuery.fn.extend({
// 取出函数队列,或函数入队
queue: function( type, data ) { ... },
// 函数出队,并执行
dequeue: function( type ) { ... },
// 延迟函数出队执行
delay: function( time, type ) { ... },
// 清空函数队列
clearQueue: function( type ) { ... },
// 观察函数队列和计数器是否完成,返回异步队列只读副本
promise: function( type, object ) { ... }
});
设置一个定时器,使得匹配元素关联的函数队列中后续的函数延迟出队和执行。
通过调用方法 .queue( type, data ) 向关联的函数队列中插入一个新函数,在该函数内通过 setTimeout 延迟下一个函数的出队时间。
返回一个异步队列的只读副本,观察每个匹配元素关联的某个类型的队列和计数器是否完成。
当每个匹配元素关联的某个类型的函数队列(type +“queue”)变为空队列,计数器(type +“mark”)变为 0,则触发异步队列的成功回调函数,上下文和参数是调用方法 .promise() 的集合(即 jQuery 对象);
如果队列和计数器不存在,则立即触发成功回调函数。
// DOM遍历
jQuery.each({
// 遍历函数
parent: function( elem ) { ... },
parents: function( elem ) { ... },
parentsUntil: function( elem, i, until ) { ... },
next: function( elem ) { ... },
prev: function( elem ) { ... },
nextAll: function( elem ) { ... },
prevAll: function( elem ) { ... },
nextUntil: function( elem, i, until ) { ... },
prevUntil: function( elem, i, until ) { ... },
siblings: function( elem ) { ... },
children: function( elem ) { ... },
contents: function( elem ) { ... }
}, function( name, fn ) {
// 公开方法,模板函数
jQuery.fn[ name ] = function( until, selector ) { ... };
});
jQuery.extend({
// 工具函数
filter: function( expr, elems, not ) { ... },
dir: function( elem, dir, until ) { ... },
nth: function( cur, result, dir, elem ) { ... },
sibling: function( n, elem ) { ... }
});
BY @nuysoft 高云 一淘-UX-墨智