您的位置:首页 > Web前端 > JQuery

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

2017-08-24 23:51 417 查看
$.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++ )
ccaf
{
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.width和oDiv.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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: