前提:
这里是349行开始的,调用jQuery.extend为jQuery添加的一些的属性,设计比较底层,当然,有些会涉及到jQuery.Callbacks和jQuery.Deferred,再这里就暂时放过,之后再解析。
jQuery.extend,在之前就已经讲过了,在这里,输入的是一个对象,意义就是把这个对象中的属性挂载到jQuery,使得外部可以直接使用jQuery或者$对对象进行调用。
一些需要了解,内部已经声明好的、可以直接调用的变量,在21行开始的首页就有声明:
- _jQuery = window.jQuery:暂存外部的jQuery变量
- _$ = window.$:暂存外部的$变量
- class2type = {}:一个对象,目前是空对象,在844行会被赋值为代表变量类型
- core_deletedIds = []:数组,用于存储已删除数据缓存id的列表
- core_version = "2.0.3":代表jQuery版本的字符串
- core_concat = core_deletedIds.concat:数组地concat方法,将两个数组拼接在一起。
- core_push = core_deletedIds.push:数组的push压栈方法
- core_indexOf = core_deletedIds.indexOf:数组的indexOf返回元素的下标,不存在就返回-1。
- core_toString = class2type.toString:对象的toString方法。
- core_hasOwn = class2type.hasOwnProperty:对象的hasOwnProperty方法,用于判断给定的属性是否在当前实例对象中。
- core_trim = core_version.trim:字符串的trim方法,用于去除字符串首位的空格
- rmsPrefix = /^-ms-/:正则
- rdashAlpha = /-([\da-z])/gi:正则
- fcamelCase:将字符串转成大写
function(all, letter) {
return letter.toUpperCase();
},
- isArraylike:判断是否是类数组,类数组有以下几种:当类型是节点,且具备长度;数组;类型不是函数、window,且具备长度属性
function isArraylike( obj ) {
var length = obj.length,
type = jQuery.type( obj );
if ( jQuery.isWindow( obj ) ) {
return false;
}
if ( obj.nodeType === 1 && length ) {
return true;
}
return type === "array" || type !== "function" &&
( length === 0 ||
typeof length === "number" && length > 0 && ( length - 1 ) in obj );
}
属性:
expando:
"jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
core_version在源码49行,是用来代表版本的字符串"2.0.3",(core_version = "2.0.3")在这里用作字符串的拼接,expando就是一个字符串,使用Math.random()使得字符串是独一无二的,(Unique for each copy of jQuery on the page...总觉得有点不保险)expando就是一个用来表示每个页面的jQuery标识。
noConflict:
noConflict: function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
}
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
},
jQuery插件会在外部使用一个jQuery或者$的变量,如果,之前已经有jQuery或者$的变量的话,jQuery就会将它保存下来,即代码38行和414行的 _jQuery = window.jQuery 和 _$ = window.$ 。这个方法就是根据输入的参数,将jQuery和$变量名归还之前的变量,然后返回内部的jQuery。结果如下:
isReady、readyWait、holdReady、ready
涉及到了之后的jQuery.Callbacks和jQuery.Deferred,暂时放过,没什么影响,在这里也只是jQuery的属性。
type:
type: function( obj ) {
if ( obj == null ) {
return String( obj );
}
return typeof obj === "object" || typeof obj === "function" ?
class2type[ core_toString.call(obj) ] || "object" :
typeof obj;
}
class2type是一个代表对象类型的对象,原本是一个空对象,让根据内部的代码处理之后(源码844行目前可以不关心如何处理的),结果如下:
core_toString则是class2type的toString函数方法,在这里,core_toString.call(obj)就相当于obj.toString()。
type的作用就是输入的参数,更根据其类型,比原生的typeof更细致的返回参数的类型。结果如下:
isFunction、isArray、isWindow、isNumeric
isFunction: function(obj) {
return jQuery.type(obj) === "function";
},
isArray: Array.isArray,
isWindow: function(obj) {
return obj != null && obj === obj.window;
},
isNumeric: function(obj) {
return ! isNaN(parseFloat(obj)) && isFinite(obj);
},
用来判断输入的参数是否是指定的类型,isFunction直接调用jQuery.type进行判断;isArray直接调用原生的isArray进行判断(有原生函数的情况下,尽可能地使用原生函数,因为这样快一点);isWindow则是根据window地一个特性,window对象地window属性指向自己(如果有个人很无聊地创建一个window属性指向自己的对象,这也是能过判断的......);isNumeric是使用数字地特性来判断(parseFloat接收地数据,不是数字的话,就会返回NaN,被isNaN判断是NaN的话,就会取true;isFinite则是判断数字是否是有限数值,是的话取true)。
isPlainObject:
isPlainObject: function( obj ) {
if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
return false;
}
try {
if ( obj.constructor &&
!core_hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
return false;
}
} catch ( e ) {
return false;
}
return true;
},
用来判断对象是否是自定义的对象。(在jQuery中节点、正则、数组等都被视作对象,可以拥有属性)
再次判断,参数必须存在constructor(构造函数,可以假象为类);core_hasOwn,相当于对象方法hasOwnProperty,这里地core_hasOwn.call( obj.constructor.prototype, "isPrototypeOf" )相当于obj.constructor.prototyp.hasOwnProperty(isPrototypeOf),isPrototypeOf是每个自定义对象都会有的方法。用于判断是否是自定义对象。(具体知识需要了解Object类型、原型的相关知识)。
结果如下:
isEmptyObject:
isEmptyObject: function(obj) {
var name;
for (name in obj) {
return false;
}
return true;
}
使用for in,判断这个对象中是否存在属性。(如果设置对象的Enumerable特性为false的话,会对这个方法造成影响)。结果如下:
error:
error: function(msg) {
throw new Error(msg);
},
会直接抛出一个js错误对象。
parseHTML:
涉及到了之后的jQuery.Callbacks和jQuery.Deferred以及DOM操作,暂时放过,没什么影响。大致功能就是解析html字符串为dom。
parseJSON:
JSON.parse
直接调用原生的JSON.parse方法实现对json对象的解析。结果如下:
parseXML:
parseXML: function(data) {
var xml, tmp;
if (!data || typeof data !== "string") {
return null;
}
try {
tmp = new DOMParser();
xml = tmp.parseFromString(data, "text/xml");
} catch(e) {
xml = undefined;
}
if (!xml || xml.getElementsByTagName("parsererror").length) {
jQuery.error("Invalid XML: " + data);
}
return xml;
},
将字符串解析为xml。
noop:
noop: function() {},
内部的一个空函数
globalEval:
globalEval: function(code) {
var script, indirect = eval;
code = jQuery.trim(code);
if (code) {
if (code.indexOf("use strict") === 1) {
script = document.createElement("script");
script.text = code;
document.head.appendChild(script).parentNode.removeChild(script);
} else {
indirect(code);
}
}
}
输入js代码,并且将它作为全局的<script>标签中的内容进行执行。
就是,先调用jQuery.trim,去除字符串首位的空格,然后使用indexOf,判断是否存在严格模式,
如果不存在严格模式的话,就直接调用indirect = eval(eval方法,将传入字符串作为js代码执行)执行;如果存在严格模式的话,就创建一个script标签,将js代码放置进去,马上执行,然后移除标签。
结果如下:(代表严格模式的字符串,和其他代码在同一行的话,会报错)
camelCase:
camelCase: function( string ) {
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
},
通过 rmsPrefix = /^-ms-/,将字符串开始的-ms-换成ms-,同时,将ms后的-删除,-之后的首字母大写。(这里涉及到了replace字符串原生函数的用法),结果如下:
nodeName:
nodeName: function( elem, name ) {
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
},
输入两个参数,第一个是dom节点,第二个是字符串,判断dom节点的名称是否和字符串一样。结果如下:
each:
each: function(obj, callback, args) {
var value, i = 0,
length = obj.length,
isArray = isArraylike(obj);
if (args) {
if (isArray) {
for (; i < length; i++) {
value = callback.apply(obj[i], args);
if (value === false) {
break;
}
}
} else {
for (i in obj) {
value = callback.apply(obj[i], args);
if (value === false) {
break;
}
}
}
} else {
if (isArray) {
for (; i < length; i++) {
value = callback.call(obj[i], i, obj[i]);
if (value === false) {
break;
}
}
} else {
for (i in obj) {
value = callback.call(obj[i], i, obj[i]);
if (value === false) {
break;
}
}
}
}
return obj;
},
对每一个类数组内的元素,执行函数callback,callback的第一个参数是对于下标的元素,如果存在参数,第二的参数就是参数。
trim:
trim: function(text) {
return text == null ? "": core_trim.call(text);
},
如果是null或者undefined的话,返回null,如果不是的话,就执行trim函数(trim是字符串的函数trim),去除首尾的空格。结果如下:
makeArray:
makeArray: function(arr, results) {
var ret = results || [];
if (arr != null) {
if (isArraylike(Object(arr))) {
jQuery.merge(ret, typeof arr === "string" ? [arr] : arr);
} else {
core_push.call(ret, arr);
}
}
return ret;
},
传入两个参数,如果results不存在,则使用空数组[]代替第一个参数。如果arr是类数组的话,判断是否是字符串,再调用merge(方法在后面,建议先看merge)把它以不同的形式合并到ret中,如果不是的话,就把它当作元素,调用core_push(相当于数组的push函数)压入第一个数组中,成为最后一个元素。(results不是类数组且布尔转化是true的话,就会返回result)。结果如下:
inArray:
inArray: function(elem, arr, i) {
return arr == null ? -1 : core_indexOf.call(arr, elem, i);
},
从第i个下标判断元素再数组中的位置(不存在的话,就默认i为0)。core_indexOf.call(arr, elem, i)相当于,arr.indexOf(elem, i)。结果如下:
merge:
merge: function(first, second) {
var l = second.length,
i = first.length,
j = 0;
if (typeof l === "number") {
for (; j < l; j++) {
first[i++] = second[j];
}
} else {
while (second[j] !== undefined) {
first[i++] = second[j++];
}
}
first.length = i;
return first;
},
输入元素,如果都是类数组的话,将第二个参数的元素,合并到第一个参数,并返回第一个参数。
只要有一个不是类数组的话,就返回第一个参数。(第一个参数不是数组的话,i会变成NaN,无法赋值,第二个参数没有元素、长度,直接返回第一个元素)
grep:
grep: function(elems, callback, inv) {
var retVal, ret = [],
i = 0,
length = elems.length;
inv = !!inv;
for (; i < length; i++) {
retVal = !!callback(elems[i], i);
if (inv !== retVal) {
ret.push(elems[i]);
}
}
return ret;
},
过滤数组,类似于数组的方法filter,不过加了一个inv,可以控制条件,决定是否相反条件地过滤。结果如下:
map:
map: function(elems, callback, arg) {
var value, i = 0,
length = elems.length,
isArray = isArraylike(elems),
ret = [];
if (isArray) {
for (; i < length; i++) {
value = callback(elems[i], i, arg);
if (value != null) {
ret[ret.length] = value;
}
}
} else {
for (i in elems) {
value = callback(elems[i], i, arg);
if (value != null) {
ret[ret.length] = value;
}
}
}
return core_concat.apply([], ret);
},
类似于数组的方法map,根据传入的元素是类数组还是对象,采用for循环和for in地方式护理,将元素传入callback中,返回结果,将结果传入ret。最后将类数组通过concat,彻底转化为数组。结果如下:
guid、proxy:
guid: 1,
proxy: function(fn, context) {
var tmp, args, proxy;
if (typeof context === "string") {
tmp = fn[context];
context = fn;
fn = tmp;
}
if (!jQuery.isFunction(fn)) {
return undefined;
}
args = core_slice.call(arguments, 2);
proxy = function() {
return fn.apply(context || this, args.concat(core_slice.call(arguments)));
};
proxy.guid = fn.guid = fn.guid || jQuery.guid++;
return proxy;
},
与后面的事件相关,不过由于本身没有引用其他复杂的函数或者变量,所以就可以解析一下它的功能。
proxy有两种输入参数的方法jQuery.proxy( function, context )以及jQuery.proxy( context, name )。
jQuery(function, context),输入一个函数和一个函数的上下文(this,如果context转化为false的话,上下文就会是jQuery)。如果这两个参数之后,还有参数的话,就会被放入args ,然后内部创建一个函数proxy,调用apply,将context改为fn的tihs,传入参数,返回执行函数。
将fn添加一个guid属性,guid加一(如果以及赋过值了,就不许加一),guid赋值给内部proxy,返回proxy。
jQuery(context, name),则是一个对象中属性是函数,传入这个对象和属性名,然后将函数的上下文this转为对象,其他于之前一样。
案例如下:
access:
access: function(elems, fn, key, value, chainable, emptyGet, raw) {
var i = 0,
length = elems.length,
bulk = key == null;
if (jQuery.type(key) === "object") {
chainable = true;
for (i in key) {
jQuery.access(elems, fn, i, key[i], true, emptyGet, raw);
}
} else if (value !== undefined) {
chainable = true;
if (!jQuery.isFunction(value)) {
raw = true;
}
if (bulk) {
if (raw) {
fn.call(elems, value);
fn = null;
} else {
bulk = fn;
fn = function(elem, key, value) {
return bulk.call(jQuery(elem), value);
};
}
}
if (fn) {
for (; i < length; i++) {
fn(elems[i], key, raw ? value: value.call(elems[i], i, fn(elems[i], key)));
}
}
}
return chainable ? elems:
bulk ? fn.call(elems) : length ? fn(elems[0], key) : emptyGet;
},
多功能值操作。
输入参数elems, fn, key, value, chainable, emptyGet, raw。key表示属性关键字;value表述属性值;chainable表示是设置属性值(true)还是获取属性值(false);emptyGet表示什么都没获取到,空;raw表示value是否为函数
首先创建几个变量,i = 0,用于遍历的辅助变量;length = elems.length,表示元素数组的长度;bulk = key == null,表示key是否为null。
如果key属性关键字是对象的话,被视作是操作多个值,表示这个对象中的各个属性内容才是属性值,key只是个集合,将chainable赋值为true,然后使用for in遍历,递归使用jQuery.access。
在key不是对象的基础上,
- 如果value为undefined的话,直接返回结果,(chainable是true,目的是设置参数,即key为对象或者key、value都存在的情况下,返回元素;反之,目的是取参数,就继续判断,如果key存在,就直接对fn传入参数elems执行返回结果,如果key不存在就继续判断,如果元素集合elems存在长度,说明是多个元素,那就执行fn传入第一个元素elems[0]和key,反之就返回emptyGet表示没有获取到属性)。
- 如果value不为undefined的话,先将chainable设置为true,然后判断是否是函数,是函数的话,设置raw为true。
之后再次判断,如果bulk存在(key存在,不会null)的话,就根据raw的值,进行不同的操作,如果raw为true的话,fn只用call传入elems, value执行函数,之后fn=null;raw为false的话,就将fn赋值给bulk保存,fn赋值为新的函数。
如果fn存在的话,就遍历元素执行fn,传入的参数(其中的个参数,复合内容有点多,不是很清楚如果执行了)
流程如下:
掌握的不是很好,可以参考https://www.cnblogs.com/hhstuhacker/p/jquery-access-source-advance.html
now:
now: Date.now,
返回当前的时间戳。结果如下:
swap:
swap: function(elem, options, callback, args) {
var ret, name, old = {};
for (name in options) {
old[name] = elem.style[name];
elem.style[name] = options[name];
}
ret = callback.apply(elem, args || []);
for (name in options) {
elem.style[name] = old[name];
}
return ret;
}
对元素样式进行指定的变化后,进行操作,在进行样式的还原。
for in,遍历元素节点的样式,old暂存,再给元素节点赋予新的样式,之后callback对元素进行操作,返回结果ret,再for in还原元素节点样式,最后返回ret。
小结:
结合些被继承的方法,再联系jQuery.extend函数,可以了解到,jQuery有些地方,并不是先声明好方法,然后再调用。内部的代码之间的联系,并不是顺序的,对源码的解读,很不友好。
在jQuery中,个人感觉,将类数组都当作数组使用。
源码:349行--------817行
jQuery.extend({
// Unique for each copy of jQuery on the page
expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
noConflict: function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
}
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
readyWait: 1,
// Hold (or release) the ready event
holdReady: function( hold ) {
if ( hold ) {
jQuery.readyWait++;
} else {
jQuery.ready( true );
}
},
// Handle when the DOM is ready
ready: function( wait ) {
// Abort if there are pending holds or we're already ready
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
return;
}
// 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").off("ready");
}
},
// 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 ) {
return jQuery.type(obj) === "function";
},
isArray: Array.isArray,
isWindow: function( obj ) {
return obj != null && obj === obj.window;
},
isNumeric: function( obj ) {
return !isNaN( parseFloat(obj) ) && isFinite( obj );
},
type: function( obj ) {
if ( obj == null ) {
return String( obj );
}
// Support: Safari <= 5.1 (functionish RegExp)
return typeof obj === "object" || typeof obj === "function" ?
class2type[ core_toString.call(obj) ] || "object" :
typeof obj;
},
isPlainObject: function( obj ) {
// Not plain objects:
// - Any object or value whose internal [[Class]] property is not "[object Object]"
// - DOM nodes
// - window
if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
return false;
}
// Support: Firefox <20
// The try/catch suppresses exceptions thrown when attempting to access
// the "constructor" property of certain host objects, ie. |window.location|
// https://bugzilla.mozilla.org/show_bug.cgi?id=814622
try {
if ( obj.constructor &&
!core_hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
return false;
}
} catch ( e ) {
return false;
}
// If the function hasn't returned already, we're confident that
// |obj| is a plain object, created by {} or constructed with new Object
return true;
},
isEmptyObject: function( obj ) {
var name;
for ( name in obj ) {
return false;
}
return true;
},
error: function( msg ) {
throw new Error( msg );
},
// data: string of html
// context (optional): If specified, the fragment will be created in this context, defaults to document
// keepScripts (optional): If true, will include scripts passed in the html string
parseHTML: function( data, context, keepScripts ) {
if ( !data || typeof data !== "string" ) {
return null;
}
if ( typeof context === "boolean" ) {
keepScripts = context;
context = false;
}
context = context || document;
var parsed = rsingleTag.exec( data ),
scripts = !keepScripts && [];
// Single tag
if ( parsed ) {
return [ context.createElement( parsed[1] ) ];
}
parsed = jQuery.buildFragment( [ data ], context, scripts );
if ( scripts ) {
jQuery( scripts ).remove();
}
return jQuery.merge( [], parsed.childNodes );
},
parseJSON: JSON.parse,
// Cross-browser xml parsing
parseXML: function( data ) {
var xml, tmp;
if ( !data || typeof data !== "string" ) {
return null;
}
// Support: IE9
try {
tmp = new DOMParser();
xml = tmp.parseFromString( data , "text/xml" );
} catch ( e ) {
xml = undefined;
}
if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
jQuery.error( "Invalid XML: " + data );
}
return xml;
},
noop: function() {},
// Evaluates a script in a global context
globalEval: function( code ) {
var script,
indirect = eval;
code = jQuery.trim( code );
if ( code ) {
// If the code includes a valid, prologue position
// strict mode pragma, execute code by injecting a
// script tag into the document.
if ( code.indexOf("use strict") === 1 ) {
script = document.createElement("script");
script.text = code;
document.head.appendChild( script ).parentNode.removeChild( script );
} else {
// Otherwise, avoid the DOM node creation, insertion
// and removal by using an indirect global eval
indirect( code );
}
}
},
// Convert dashed to camelCase; used by the css and data modules
// Microsoft forgot to hump their vendor prefix (#9572)
camelCase: function( string ) {
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
},
nodeName: function( elem, name ) {
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
},
// args is for internal usage only
each: function( obj, callback, args ) {
var value,
i = 0,
length = obj.length,
isArray = isArraylike( obj );
if ( args ) {
if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback.apply( obj[ i ], args );
if ( value === false ) {
break;
}
}
} else {
for ( i in obj ) {
value = callback.apply( obj[ i ], args );
if ( value === false ) {
break;
}
}
}
// A special, fast, case for the most common use of each
} else {
if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback.call( obj[ i ], i, obj[ i ] );
if ( value === false ) {
break;
}
}
} else {
for ( i in obj ) {
value = callback.call( obj[ i ], i, obj[ i ] );
if ( value === false ) {
break;
}
}
}
}
return obj;
},
trim: function( text ) {
return text == null ? "" : core_trim.call( text );
},
// results is for internal usage only
makeArray: function( arr, results ) {
var ret = results || [];
if ( arr != null ) {
if ( isArraylike( Object(arr) ) ) {
jQuery.merge( ret,
typeof arr === "string" ?
[ arr ] : arr
);
} else {
core_push.call( ret, arr );
}
}
return ret;
},
inArray: function( elem, arr, i ) {
return arr == null ? -1 : core_indexOf.call( arr, elem, i );
},
merge: function( first, second ) {
var l = second.length,
i = first.length,
j = 0;
if ( typeof l === "number" ) {
for ( ; j < l; j++ ) {
first[ i++ ] = second[ j ];
}
} else {
while ( second[j] !== undefined ) {
first[ i++ ] = second[ j++ ];
}
}
first.length = i;
return first;
},
grep: function( elems, callback, inv ) {
var retVal,
ret = [],
i = 0,
length = elems.length;
inv = !!inv;
// Go through the array, only saving the items
// that pass the validator function
for ( ; i < length; i++ ) {
retVal = !!callback( elems[ i ], i );
if ( inv !== retVal ) {
ret.push( elems[ i ] );
}
}
return ret;
},
// arg is for internal usage only
map: function( elems, callback, arg ) {
var value,
i = 0,
length = elems.length,
isArray = isArraylike( elems ),
ret = [];
// Go through the array, translating each of the items to their
if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback( elems[ i ], i, arg );
if ( value != null ) {
ret[ ret.length ] = value;
}
}
// Go through every key on the object,
} else {
for ( i in elems ) {
value = callback( elems[ i ], i, arg );
if ( value != null ) {
ret[ ret.length ] = value;
}
}
}
// Flatten any nested arrays
return core_concat.apply( [], ret );
},
// A global GUID counter for objects
guid: 1,
// Bind a function to a context, optionally partially applying any
// arguments.
proxy: function( fn, context ) {
var tmp, args, proxy;
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 ) ) {
return undefined;
}
// Simulated bind
args = core_slice.call( arguments, 2 );
proxy = function() {
return fn.apply( context || this, 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;
},
// 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, raw ) {
var i = 0,
length = elems.length,
bulk = key == null;
// Sets many values
if ( jQuery.type( key ) === "object" ) {
chainable = true;
for ( i in key ) {
jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
}
// Sets one value
} else if ( value !== undefined ) {
chainable = true;
if ( !jQuery.isFunction( value ) ) {
raw = true;
}
if ( bulk ) {
// Bulk operations run against the entire set
if ( raw ) {
fn.call( elems, value );
fn = null;
// ...except when executing function values
} else {
bulk = fn;
fn = function( elem, key, value ) {
return bulk.call( jQuery( elem ), value );
};
}
}
if ( fn ) {
for ( ; i < length; i++ ) {
fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
}
}
}
return chainable ?
elems :
// Gets
bulk ?
fn.call( elems ) :
length ? fn( elems[0], key ) : emptyGet;
},
now: Date.now,
// A method for quickly swapping in/out CSS properties to get correct calculations.
// Note: this method belongs to the css module but it's needed here for the support module.
// If support gets modularized, this method should be moved back to the css module.
swap: function( elem, options, callback, args ) {
var ret, name,
old = {};
// Remember the old values, and insert the new ones
for ( name in options ) {
old[ name ] = elem.style[ name ];
elem.style[ name ] = options[ name ];
}
ret = callback.apply( elem, args || [] );
// Revert the old values
for ( name in options ) {
elem.style[ name ] = old[ name ];
}
return ret;
}
});