3.jQuery.extend()扩展的一些工具方法

前提:

这里是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不是对象的基础上,

  1. 如果value为undefined的话,直接返回结果,(chainable是true,目的是设置参数,即key为对象或者key、value都存在的情况下,返回元素;反之,目的是取参数,就继续判断,如果key存在,就直接对fn传入参数elems执行返回结果,如果key不存在就继续判断,如果元素集合elems存在长度,说明是多个元素,那就执行fn传入第一个元素elems[0]和key,反之就返回emptyGet表示没有获取到属性)。
  2. 如果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;
	}
});

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值