zoukankan      html  css  js  c++  java
  • jQuery 源码分析6: jQuery 基本静态方法(二)

      1 jQuery.extend({
      2 
      3 // 遍历obj的所有值
      4 // args 这参数只能内部调用的会用到
      5 // 注意到,如果回调函数调用失败会直接跳出并中止遍历
      6 // 当有args数组时,使用apply调用,否则使用call调用
      7 each: function( obj, callback, args ) {
      8      var value,
      9           i = 0,
     10           length = obj.length,
     11           isArray = isArraylike( obj );
     12       if ( args ) {     // 内部调用时才会有args
     13           if ( isArray ) {     // obj是Array
     14 
     15                for ( ; i < length; i++ ) {
     16                     value = callback.apply( obj[ i ], args );
     17                     if ( value === false ) {
     18                         break;
     19                     }
     20                }
     21           } else {             // obj是Object
     22 
     23 
     24           for ( i in obj ) {
     25 
     26               value = callback.apply( obj[ i ], args );
     27 
     28               if ( value === false ) {
     29 
     30                    break;
     31 
     32               }
     33 
     34           }
     35 
     36           }
     37     // 最常用的each使用方式
     38     } else {
     39          if ( isArray ) {     // obj是Array
     40               for ( ; i < length; i++ ) {
     41                    value = callback.call( obj[ i ], i, obj[ i ] );   // 回调函数会获取i 和 对应的属性
     42                    if ( value === false ) {
     43                         break;
     44                    }
     45               }
     46          } else {             // obj是Object
     47               for ( i in obj ) {
     48                    value = callback.call( obj[ i ], i, obj[ i ] );
     49                    if ( value === false ) {
     50                         break;
     51                    }
     52               }
     53           }
     54      }
     55      return obj;
     56 },
     57 
     58 // 支持: Android<4.1, IE<9
     59 // rtrim = /^[suFEFFxA0]+|[suFEFFxA0]+$/g
     60 // 删除 BOM and NBSP 
     61 trim: function( text ) {
     62      return text == null ?
     63             "" :
     64             ( text + "" ).replace( rtrim, "" );
     65 },
     66 
     67 // results参数仅限内部调用
     68 // 将arr变成一个Array
     69 // 如果有results,arr会合并到results后面
     70 // 如果arr是'string',则会转换为[arr]然后合并到Array上
     71 makeArray: function( arr, results ) {
     72      var ret = results || [];
     73      if ( arr != null ) {
     74           if ( isArraylike( Object(arr) ) ) {
     75                jQuery.merge( ret,
     76                           typeof arr === "string" ?
     77                          [ arr ] : arr
     78                );
     79           } else {
     80                push.call( ret, arr );
     81           }
     82      }
     83      return ret;
     84 },
     85 
     86 // 判断elem是否在arr这个数组上
     87 // i是检索的起始index
     88 inArray: function( elem, arr, i ) {
     89      var len;
     90      if ( arr ) {
     91           if ( indexOf ) {
     92                return indexOf.call( arr, elem, i );     // 调用Array.indexOf
     93           }
     94           len = arr.length;
     95           i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;     // 如果i<0,则设i为len+i
     96           for ( ; i < len; i++ ) {
     97           // 跳过对稀疏数组的访问?
     98           // Skip accessing in sparse arrays
     99                if ( i in arr && arr[ i ] === elem ) {
    100                     return i;
    101                }
    102           }
    103      }
    104      return -1;
    105 },
    106 
    107  // 把second合并到first上
    108 merge: function( first, second ) {
    109     var len = +second.length,
    110         j = 0,
    111         i = first.length;
    112     while ( j < len ) {
    113         first[ i++ ] = second[ j++ ];
    114     }
    115     // 支持: IE<9
    116     // 如果类数组对象没有length,因此.length不是一个数字,例如NodeLists
    117     if ( len !== len ) {
    118          while ( second[j] !== undefined ) {
    119              first[ i++ ] = second[ j++ ];
    120          }
    121     }
    122     first.length = i;
    123     return first;
    124 },
    125 
    126 // 筛选遍历数组
    127 // callback用于判断是否符合
    128 // invert表示与callback的结果相反,即希望保留callback返回值为false的元素
    129 grep: function( elems, callback, invert ) {
    130      var callbackInverse,
    131          matches = [],
    132          i = 0,
    133          length = elems.length,
    134          callbackExpect = !invert;   // invert == true, 表示希望callback返回false
    135      // 遍历数组,只保留通过筛选的元素
    136      for ( ; i < length; i++ ) {
    137          callbackInverse = !callback( elems[ i ], i );
    138          if ( callbackInverse !== callbackExpect ) {
    139              matches.push( elems[ i ] );
    140          }
    141      }
    142      return matches;
    143 },
    144 
    145 // arg参数只在内部调用时使用
    146 map: function( elems, callback, arg ) {
    147     var value,
    148     i = 0,
    149     length = elems.length,
    150     isArray = isArraylike( elems ),
    151     ret = [];
    152      // 遍历数组,将其转换成新的值并放到ret数组中
    153     if ( isArray ) {
    154         for ( ; i < length; i++ ) {
    155             value = callback( elems[ i ], i, arg );
    156             if ( value != null ) {
    157                 ret.push( value );
    158             }
    159         }
    160     // 遍历对象的属性,将其转换成新的值并放到ret数组中
    161     } else {
    162         for ( i in elems ) {
    163             value = callback( elems[ i ], i, arg );
    164             if ( value != null ) {
    165                ret.push( value );
    166             }
    167         }
    168     }
    169      // 如果存在嵌套的数组,将其展开
    170     return concat.apply( [], ret );
    171 },
    172 
    173  // 对象的全局GUID计数器
    174 guid: 1,
    175 
    176  // Bind a function to a context, optionally partially applying any arguments.
    177 // 为一个function绑定一个上下文环境,
    178 proxy: function( fn, context ) {
    179     var args, proxy, tmp;
    180     // 处理: $.proxy(context, name)
    181     if ( typeof context === "string" ) {
    182         tmp = fn[ context ];      // 从参数context提取一个function
    183         context = fn;             // 将上下文设置成参数context
    184         fn = tmp;                 // 将绑定function对象设置为conext[nam]
    185     }
    186     
    187     // 确保fn是一个可调用对象
    188     // 如果不可调用,返回undefined
    189     if ( !jQuery.isFunction( fn ) ) {
    190         return undefined;
    191     }
    192     // 模拟上下文绑定
    193     args = slice.call( arguments, 2 );     // 截取fn所需要的参数
    194     proxy = function() {
    195         return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
    196     };
    197     // 为唯一的句柄设置guid,这个guid应该与原理fn的guid一样,使得它可以被移除
    198     proxy.guid = fn.guid = fn.guid || jQuery.guid++;
    199     return proxy;
    200 },
    201 
    202  // 新建一个时间对象并返回
    203 now: function() {
    204     return +( new Date() );
    205 },
    206 
    207 // jQuery不会在内核中使用,但其他项目会将一些属性设置到support中
    208 support: support
    209 
    210  
    211 
    212 });
     
     
    总结:
    • jQuery.extend在进行扩展的时候,是使用到了深拷贝,这是教科书式的用法,对Object和Array对象进行递归合并,将其中所有的属性都作拷贝。这样做的原因是在JavaScript里,对右值为Object和Array的赋值操作是执行引用而非拷贝,因此必须遍历Object和Array的属性以实现深拷贝;
    • 方法重载的技巧再次出现,如jQuery.proxy。重载的实现实际上要对参数类型、参数数量进行判断,以进行不同的处理;
    • 为了绑定函数方法的上下文环境,我们可以使用jQuery.proxy,而.proxy的实现使用到了function.apply(conext, args);
    • jQuery.grep的实现也是比较巧妙,添加一个形参invert来进行反向选择,即可以利用一个callback作出双向选择,这也是一个简单而巧妙的技巧。
  • 相关阅读:
    DataPipeline CTO陈肃:驱动软件国产化,客户需求是核心引擎
    DataPipeline王睿:业务异常实时自动化检测 — 基于人工智能的系统实战
    Q&A系列一:DataPipeline常见问题回答
    下篇丨数据融合平台DataPipeline的实际应用场景
    上篇丨数据融合平台DataPipeline的应用场景
    这些传统数据集成的痛,你还在经历吗?
    ETL的两种架构——ETL架构和ELT架构优劣势对比
    2020即将到来,看完这篇帮你详细了解数据策略
    DataPipeline丨「自定义」数据源,解决复杂请求逻辑外部数据获取难题
    SQLI-LABS LESS 1-LESS 22
  • 原文地址:https://www.cnblogs.com/elcarim5efil/p/4673106.html
Copyright © 2011-2022 走看看