jQuery中工具方法$.aaa()的源码分析

$.each(): 当只有两个参数时,callback回调函数的参数是i,obj[i],即callback(i,obj[i])

              当有三个参数时,callback回调函数的参数是args,即callback(args)

               当callback()函数的返回值是false是,会终止for循环

               callback.apply( obj[ i ], args );

               callback.call( obj[ i ], i, obj[ i ] );

              callback()函数执行的上下文环境是obj[i],相当于obj[i]调用可callback(),所以callback()函数内部的                    this 是指obj[i]

// args is for internal usage only
	each: function( obj, callback, args ) {
		var value,
			i = 0,
			length = obj.length,//数组、类数组和this指针都有length属性,但是{}没有length属性
			isArray = isArraylike( obj );//数组、类数组和this指针返回true
        //args参数为真,内部使用
		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 {
			//如果是数组 类数组或this,使用for语句进行循环
			if ( isArray ) {
				for ( ; i < length; i++ ) {
					value = callback.call( obj[ i ], i, obj[ i ] );//将下标和对应的元素传给回调函数

					if ( value === false ) {
						break;//用来终止循环遍历
					}
				}
			} else {//如果是{}则使用for(...in ...)进行遍历
				for ( i in obj ) {
					value = callback.call( obj[ i ], i, obj[ i ] );

					if ( value === false ) {
						break;
					}
				}
			}
		}

		return obj;
	},

$('#id').each():

each: function( callback, args ) {
		return jQuery.each( this, callback, args );
	},
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>无标题文档</title>
<script src="jquery-2.0.3.js"></script>
<script>
	$(function(){
		$('li').each(function(i,item){
			console.log(i);
			console.log(item);
			console.log(item===$('li')[0]);
		})
	console.log($('li'));
	console.log(isArraylike( $('li') ));//true,jQuery实例是一个类数组
	console.log($('li')[0].nodeType);//1,说明是元素节点
	var arr = Array.prototype.slice.call($('li'));
	console.log(arr);
	console.log(arr instanceof Array);//true
	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 );
	}
	})
</script>
</head>
<body>
	<ul>
		<li>html</li>
		<li>css</li>
		<li>javascript</li>
	</ul>
</body>
</html>


jQuery中的类数组判断:

var	div1={0:'a',2:'b',length:0};
	var	div2={0:'a',2:'b',length:2};
	var	div3={0:'a',2:'b',length:3};
		
	function isArraylike( obj ) {
     var length = obj.length,
     type = jQuery.type( obj );

       if ( jQuery.isWindow( obj ) ) {
       return false;
        }

	if ( obj.nodeType === 1 && length ) {
		alert(1);
		return true;
	}
    //length===0,是因为arguments,没有参数的情况
    return type === "array" || type !== "function" &&
	( length === 0 ||
	typeof length === "number" && length > 0 && ( length - 1 ) in obj );
}
	console.log(isArraylike(div1));//true length是0,就是类数组
	console.log(isArraylike(div2));//false
	console.log(isArraylike(div3));//true
$.map():会返回一个新的数组。
// 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 );//将数组变为简单数组[[1],[2],[3]]变为[1,2,3]
	},


$.grep():过滤数组:将回调函数的返回值转换成boolean值,将第三个参数转换成boolean值,
将两者比较,若不相等,将该元素添加到一个 新的数组中,并将新的数组返回。
当第三个参数的boolean值相当于false时,相当于过滤器,满足条件的数组元素添加到新的数组中,并将新数组返回,即不写第三个参数或第三个参数的boolean值是false是相当于过滤器

//当inv为true时,将不满足条件的元素组成新数组数组并返回
grep: function( elems, callback, inv ) {
		var retVal,
			ret = [],
			i = 0,
			length = elems.length;
		inv = !!inv; //inv未写这个参数时是undefined,前面加!!会转变为false

		// 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;
	},

当没有设置参数inv时:

 var arr=[1,2,3,4] ;
   arr1=$.grep(arr,function(value,i){
   	return value>2;
   });
   alert(arr);//1,2,3,4
   alert(arr1);//3,4
当inv时true时:
arr1=$.grep(arr,function(value,i){
   	return value>2;
   },true);
   alert(arr);//1,2,3,4
   alert(arr1);//1,2

$.merge():合并数组

第一个参数必须是类数组或数组,即必须有length属性
第二个参数可以是类数组、数组,也可以是没有length属性的对象,但是属性必须有数字,必须0开头,若出现不连续,则不连续处不再合并到第一个参数
会在第一个参数基础上进行添加操作,并将第一个参数返回,第一个参数发生变化

merge: function( first, second ) {
	//{}没有length属性,但有一种特殊的,如{0:,1:,length:2},可以当做数组看待
		var l = second.length,
			i = first.length,
			j = 0;

		if ( typeof l === "number" ) {
			for ( ; j < l; j++ ) {
				first[ i++ ] = second[ j ];
			}
		} else {//用来处理没有length属性,但属性名字是0,1,2...{0:,1:,2:..}
			while ( second[j] !== undefined ) {
				first[ i++ ] = second[ j++ ];
			}
		}

		first.length = i;

		return first;
	},
$.merge()可以使下列几种形式:
console.log( $.merge(['a','b'],['c','d']) );//["a", "b", "c", "d"] 
console.log( $.merge(['a','b'],{0:'c',1:'d'}) );//["a", "b", "c", "d"] 
console.log( $.merge({0:'a',1:'b',length:2},{0:'c',1:'d'}) );//Object {0: "a", 1: "b", 2: "c", 3: "d", length: 4} 
console.log( $.merge({0:'a',1:'b',length:2},['c','d']) );//Object {0: "a", 1: "b", 2: "c", 3: "d", length: 4} 
console.log( $.merge({0:'a',1:'b',length:2},{0:'c',1:'d',3:'e'}) );//Object {0: "a", 1: "b", 2: "c", 3: "d", length: 4} 
$.makeArray():类数组转真数组:第二个参数是jQuery内部使用的
//result参数是内部使用,我们使用时,用一个参数,返回真数组
makeArray: function( arr, results ) {
		var ret = results || [];

		if ( arr != null ) {
			if ( isArraylike( Object(arr) ) ) {//Object("hello")是类数组
				//如果是类数组,则进行数组合并,如果不是,就用push()方法
				jQuery.merge( ret,
					typeof arr === "string" ?
					[ arr ] : arr
				);
			} else {
				core_push.call( ret, arr );//如果不是类数组元素,直接用数组方法push
			}
		}

		return ret;
	},
var obj = {0: 'a',1: 'b', 2: 'c',length:3};
var str = 'hello';
var num = 123;
console.log($.makeArray(obj));//["a", "b", "c"] 
console.log($.makeArray(str));//["hello"]
console.log($.makeArray(num));//[123]
//类数组以外的元素也能转化成数组,如字符串、数字,但是将整个数字、字符串变成一个数组元素

$.inArray():数组版的indexOf(),返回元素在数组中的下标位置

第三个参数i表示查找的其实位置,默认从下标0处开始查找

inArray: function( elem, arr, i ) {
		return arr == null ? -1 : core_indexOf.call( arr, elem, i );
	},
var arr = ['a','b','c','d','a'];
console.log( $.inArray( 'a' , arr ) );//0
console.log( $.inArray( 'a' , arr , 1 ) );//4

$.proxy():修改this指向

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;
	},
function show(n1,n2){
	console.log(n1); //3
	console.log(n2); //4
	console.log(this);//#document
  }
   $.proxy(show,document,3)(4);
var obj = {
	show : function(){
		console.log(this);//Object {show: function}
	}
 };

  $(document).click( $.proxy(obj,'show') );
//$.proxy(obj,'show') ->  $.proxy(obj.show,obj)

$.access():多功能值操作,jQuery内部使用

$('#div1').css('width') );
$('#div1').css('background','yellow');
$('#div1').css({ background : 'yellow' , width : '300px' });
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;
	}

$.swap():先将元素的样式保存起来,再设置新的属性样式,执行回调函数后,再还原样式,最终返回回调函数的返回值。

用途:原生js中,不能获取display:none的元素的offsetWidth属性,但是jQuery却可以,就是利用了该函数。

注意:display:none的元素的width属性可以获得,oDiv.style.widthoDiv.offsetWidth,width属性挂在元素的style属性下,

offsetWidth属性直接挂在元素的属性下

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;
	}
$(function(){
	
	console.log( $('#div1').outerWidth());//100
	
	console.log( $('#div1').get(0).style.width );//100px
	
	console.log( $('#div1').get(0).offsetWidth );//0
	
	var oDiv = $('#div1').get(0);
	var options = {'display':'block','visibility':'hidden','position':'absolute'};
	var width = $.swap(oDiv,options,function(){
		return oDiv.offsetWidth;
	});
	console.log(width);//100
});
<div id="div1" style="width:100px; height:100px; background:red;display:none;"></div>













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值