惟有于技术中才能明得真相

jQuery源代码阅读(三):Utilities

jQuery Utilities就是一些实用函数,定义在jQuery对象中。它们大多数都比较简单,但因为通用所以在源代码的许多地方都有用到,正因为如此,其它某 些语言内置就提供这些功能,如果熟悉这些语言,则不需要看源代码也能够清楚其功能。不像其它函数,这部分要介绍的函数都比较独立,可以单独介绍。

(1)jQuery.each
这个函数可能是用得最多的一个,它用于对数组或对象进行遍历。下面是它的源代码实现:

 670     // args is for internal usage only
 671     each: functionobject, callback, args ) {
 672         var name, i = 0, length = object.length;
 673
 674         if ( args ) {
 675             if ( length === undefined ) {
 676                 for ( name in object )
 677                     if ( callback.apply( object[ name ], args ) === false )
 678                         break;
 679             } else
 680                 for ( ; i < length; )
 681                     if ( callback.apply( object[ i++ ], args ) === false )
 682                         break;
 683
 684         // A special, fast, case for the most common use of each
 685         } else {
 686             if ( length === undefined ) {
 687                 for ( name in object )
 688                     if ( callback.call( object[ name ], name, object[ name ] ) === false )
 689                         break;
 690             } else
 691                 for ( var value = object[0];
 692                     i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
 693         }
 694
 695         return object;
 696     },


第 3个参数args仅在内部使用(我搜索整个jQuery源代码也没有看到在哪里有用),通过它可以传递额外的参数,这里略去不讲,也就是代码的第 674-683行。第686行判断object不是数组(或类数组),即一个普通对象。第687-689行使用for...in循环对它的所有属性遍历, 对每个函数调用callback回调函数,它接受两个参数,一个是属性名,一个是属性名对应的值,也就是object[属性名],它也是this对象。另 外如果回调函数如果返回false,则中断遍历。第686-694则是对数组进行遍历,回调函数也接受两个参数,第一个为索引,第二个数组中该索引处的 值,this也是这个对象。同样地,当回调函数返回false时,中断循环。each函数最终返回object,即要遍历的对象或数组。另外jQuery 对象也有一个each方法(即jQuery.fn.each),由于它只传递一个callback参数,它对当前jQuery对象进行遍历。

(2)jQuery.map
它用于将一个数组通过某种规则转变成另一个数组,例如要将一个数组的所有的元素变成大写,可以调用:

var upperArr = jQuery.map(arr, function(n, i) { return n.toUpperCase(); })

其源代码实现很简单:

1146     map: function( elems, callback ) {
1147         var ret = [];
1148
1149         // Go through the array, translating each of the items to their
1150         // new value (or values).
1151         for ( var i = 0, length = elems.length; i < length; i++ ) {
1152             var value = callback( elems[ i ], i );
1153
1154             if ( value != null )
1155                 ret[ ret.length ] = value;
1156         }
1157
1158         return ret.concat.apply( [], ret );
1159     }


它 就是对数组的每个元素进行遍历,将对它们调用callback函数,将其返回值添加到ret中,第1158行用于辗平数组,如果在1158行之前ret为 [['a', 'b'], ['c', 'd']],那么经过1158行的调用后,ret的值为['a', 'b', 'c', 'd'],这个行为可能和别的语言中的map行为不同。

(3) jQuery.extend
jQuery.extend有许多不 同的变种,最完整的版本为jQuery.extend(deep, target, object1, ..., objectN),它将object1, ..., objectN中的所有属性拷贝到target中相应属性中。其中第一个参数表示是否为深拷贝,这个参数可选,默认是浅拷贝;第二个参数是拷贝的目的对 象,这个参数也是可选,默认为this;最后的所有参数为拷贝源。这个函数是这样判断有没有提供target参数,它先判断第一个参数是不是 boolean类型,如果是表示它是deep参数,先抛开它。剩下的参数如果只有一个参数,则表示没有target,使用默认值,否则使用target就 是剩下的第一个参数,其它参数就是拷贝源。

 562 jQuery.extend = jQuery.fn.extend = function() {
 563     // copy reference to target object
 564     var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
 565
 566     // Handle a deep copy situation
 567     if ( typeof target === "boolean" ) {
 568         deep = target;
 569         target = arguments[1] || {};
 570         // skip the boolean and the target
 571         i = 2;
 572     }
 573
 574     // Handle case when target is a string or something (possible in deep copy)
 575     if ( typeof target !== "object" && !jQuery.isFunction(target) )
 576         target = {};
 577
 578     // extend jQuery itself if only one argument is passed
 579     if ( length == i ) {
 580         target = this;
 581         --i;
 582     }
 583
 584     for ( ; i < length; i++ )
 585         // Only deal with non-null/undefined values
 586         if ( (options = arguments[ i ]) != null )
 587             // Extend the base object
 588             for ( var name in options ) {
 589                 var src = target[ name ], copy = options[ name ];
 590
 591                 // Prevent never-ending loop
 592                 if ( target === copy )
 593                     continue;
 594
 595                 // Recurse if we're merging object values
 596                 if ( deep && copy && typeof copy === "object" && !copy.nodeType )
 597                     target[ name ] = jQuery.extend( deep,
 598                         // Never move original objects, clone them
 599                         src || ( copy.length != null ? [ ] : { } )
 600                     , copy );
 601
 602                 // Don't bring in undefined values
 603                 else if ( copy !== undefined )
 604                     target[ name ] = copy;
 605
 606             }
 607
 608     // Return the modified object
 609     return target;
 610 };


jQuery的Utitlies函数就讲这些,其它的一些还有如grep(对数组元素进行过滤),makeArray(将任意对象转变成数组),inArray(在数组中搜索对象返回其索引),merge(将两个数组元素合并),unique(去掉数组中重复元素)等,它们的实现也并不复杂。

0 评论: