接下去分析那个extend块,接下来是一个each函数,它对传入的数组中的每个值进行特定处理,根据返回值确定操作(明确返回 false则停止循环)
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; } } } // 不需要传入args时,这是一种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函数主要是用来去除字符串首尾的空格,优先使用浏览器中自带有的方法。makeArray则是将传入的一或两个参数转成数组返回,看源码分析如下:
trim: trim && !trim.call("\uFEFF\xA0") ? function( text ) { return text == null ? "" : trim.call( text ); } : // 优先使用自带的trim // 否则就返回自己设置的trim函数 function( text ) { return text == null ? "" : ( text + "" ).replace( rtrim, "" ); // rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g }, makeArray: function( arr, results ) { var ret = results || []; if ( arr != null ) { // 当arr为数组或类数组时,用merge(后面就会分析到) if ( isArraylike( Object(arr) ) ) { jQuery.merge( ret, typeof arr === "string" ? [ arr ] : arr ); } else { // 否则,就直接将arr作为一个元素添加到ret作为最后一项 push.call( ret, arr ); } } return ret; }
inArray是用来判断从指定位置其某个元素是否在一个array中,merge是将后一个arr融合到前一个arr中(当然,也可能是类数组)
inArray: function( elem, arr, i ) { var len; if ( arr ) { // 优先使用自带的indexOf if ( indexOf ) { return indexOf.call( arr, elem, i ); } len = arr.length; i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; for ( ; i < len; i++ ) { if ( i in arr && arr[ i ] === elem ) { return i; } } } return -1; }, merge: function( first, second ) { var len = +second.length, j = 0, i = first.length; while ( j < len ) { first[ i++ ] = second[ j++ ]; } // 为了兼容一些会返回length为NaN的情况的类数组(NodeList.....在某些浏览器中) if ( len !== len ) { while ( second[j] !== undefined ) { first[ i++ ] = second[ j++ ]; } } first.length = i; return first; },
grep作用是一个过滤的效果,对每隔元素执行一遍传入的函数,满足要求的就放入结果中。作为第三个invert参数,是为了设置是函数返回true还是false时才算通过过滤。 如果 ‘invert‘ 为 false ,则函数返回数组中由过滤函数返回 true 的元素,当‘invert‘为 true,则返回过滤函数中返回 false 的元素集。
grep: function( elems, callback, invert ) { var callbackInverse, matches = [], i = 0, length = elems.length, callbackExpect = !invert; // 循环整个elems,对每个都进行callback函数的运行 // 根据invert筛选结果 for ( ; i < length; i++ ) { callbackInverse = !callback( elems[ i ], i ); if ( callbackInverse !== callbackExpect ) { matches.push( elems[ i ] ); } } return matches; }
map和each类似,不同的是map会对每一项进行循环,不会因为返回值的问题而停止,同时会将所有非null的返回值组成数组返回。
map: function( elems, callback, arg ) { var value, i = 0, length = elems.length, isArray = isArraylike( elems ), ret = []; // 如果是数组或类数组,就用i递增循环 if ( isArray ) { for ( ; i < length; i++ ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret.push( value ); } } // 否则,就认为是object,用for..in方法 } else { for ( i in elems ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret.push( value ); } } } // 返回数组副本,这样对新数组的修改不会影响到旧数组 return concat.apply( [], ret ); }
proxy是一个可以改变执行函数上下文环境的函数,可以通过$.proxy(function(){},context)实现。(例:$( "#test" ).on( "click", $.proxy( me.test, me ) ) )。
proxy: function( fn, context ) { var args, proxy, tmp; //确定fn和context确切值 if ( typeof context === "string" ) { tmp = fn[ context ]; context = fn; fn = tmp; } // 若fn不是函数,则直接返回 if ( !jQuery.isFunction( fn ) ) { return undefined; } // 得到要传入的参数 args = slice.call( arguments, 2 ); proxy = function() { //args为在proxy中定义的变量,而arguments则是执行时会有的变量(> <解释不清楚...来个例子) //$( "#test" ).on( "click", $.proxy( me.test, me ) )运行时,arguments为[jQuery.events] return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); }; // 设置唯一的guid,这样可以在后期移除 proxy.guid = fn.guid = fn.guid || jQuery.guid++; return proxy; },
最后一个是now函数,返回现在的时间
now: function() { return +( new Date() ); }