jQuery 源码分析6: jQuery 基本静态方法(二)
 jQuery.extend({
 // 遍历obj的所有值
 // args 这参数只能内部调用的会用到
 // 注意到,如果回调函数调用失败会直接跳出并中止遍历
 // 当有args数组时,使用apply调用,否则使用call调用
 each: function( obj, callback, args ) {
      var value,
           i = 0,
           length = obj.length,
           isArray = isArraylike( obj );
       if ( args ) {     // 内部调用时才会有args
           if ( isArray ) {     // obj是Array
                for ( ; i < length; i++ ) {
                     value = callback.apply( obj[ i ], args );
                     if ( value === false ) {
                         break;
                     }
                }
           } else {             // obj是Object
           for ( i in obj ) {
               value = callback.apply( obj[ i ], args );
               if ( value === false ) {
                    break;
               }
           }
           }
     // 最常用的each使用方式
     } else {
          if ( isArray ) {     // obj是Array
               for ( ; i < length; i++ ) {
                    value = callback.call( obj[ i ], i, obj[ i ] );   // 回调函数会获取i 和 对应的属性
                    if ( value === false ) {
                         break;
                    }
               }
          } else {             // obj是Object
               for ( i in obj ) {
                    value = callback.call( obj[ i ], i, obj[ i ] );
                    if ( value === false ) {
                         break;
                    }
               }
           }
      }
      return obj;
 },
 // 支持: Android<4.1, IE<9
 // rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g
 // 删除 BOM and NBSP
 trim: function( text ) {
      return text == null ?
             "" :
             ( text + "" ).replace( rtrim, "" );
 },
 // results参数仅限内部调用
 // 将arr变成一个Array
 // 如果有results,arr会合并到results后面
 // 如果arr是'string',则会转换为[arr]然后合并到Array上
 makeArray: function( arr, results ) {
      var ret = results || [];
      if ( arr != null ) {
           if ( isArraylike( Object(arr) ) ) {
                jQuery.merge( ret,
                           typeof arr === "string" ?
                          [ arr ] : arr
                );
           } else {
                push.call( ret, arr );
           }
      }
      return ret;
 },
 // 判断elem是否在arr这个数组上
 // i是检索的起始index
 inArray: function( elem, arr, i ) {
      var len;
      if ( arr ) {
           if ( indexOf ) {
                return indexOf.call( arr, elem, i );     // 调用Array.indexOf
           }
           len = arr.length;
           i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;     // 如果i<0,则设i为len+i
           for ( ; i < len; i++ ) {
           // 跳过对稀疏数组的访问?
           // Skip accessing in sparse arrays
                if ( i in arr && arr[ i ] === elem ) {
                     return i;
                }
           }
      }
      return -1;
 },
  // 把second合并到first上
 merge: function( first, second ) {
     var len = +second.length,
         j = 0,
         i = first.length;
     while ( j < len ) {
         first[ i++ ] = second[ j++ ];
     }
     // 支持: IE<9
     // 如果类数组对象没有length,因此.length不是一个数字,例如NodeLists
     if ( len !== len ) {
          while ( second[j] !== undefined ) {
              first[ i++ ] = second[ j++ ];
          }
     }
     first.length = i;
     return first;
 },
 // 筛选遍历数组
 // callback用于判断是否符合
 // invert表示与callback的结果相反,即希望保留callback返回值为false的元素
 grep: function( elems, callback, invert ) {
      var callbackInverse,
          matches = [],
          i = 0,
          length = elems.length,
          callbackExpect = !invert;   // invert == true, 表示希望callback返回false
      // 遍历数组,只保留通过筛选的元素
      for ( ; i < length; i++ ) {
          callbackInverse = !callback( elems[ i ], i );
          if ( callbackInverse !== callbackExpect ) {
              matches.push( elems[ i ] );
          }
      }
      return matches;
 },
 // arg参数只在内部调用时使用
 map: function( elems, callback, arg ) {
     var value,
     i = 0,
     length = elems.length,
     isArray = isArraylike( elems ),
     ret = [];
      // 遍历数组,将其转换成新的值并放到ret数组中
     if ( isArray ) {
         for ( ; i < length; i++ ) {
             value = callback( elems[ i ], i, arg );
             if ( value != null ) {
                 ret.push( value );
             }
         }
     // 遍历对象的属性,将其转换成新的值并放到ret数组中
     } else {
         for ( i in elems ) {
             value = callback( elems[ i ], i, arg );
             if ( value != null ) {
                ret.push( value );
             }
         }
     }
      // 如果存在嵌套的数组,将其展开
     return concat.apply( [], ret );
 },
  // 对象的全局GUID计数器
 guid: 1,
  // Bind a function to a context, optionally partially applying any arguments.
 // 为一个function绑定一个上下文环境,
 proxy: function( fn, context ) {
     var args, proxy, tmp;
     // 处理: $.proxy(context, name)
     if ( typeof context === "string" ) {
         tmp = fn[ context ];      // 从参数context提取一个function
         context = fn;             // 将上下文设置成参数context
         fn = tmp;                 // 将绑定function对象设置为conext[nam]
     }
     // 确保fn是一个可调用对象
     // 如果不可调用,返回undefined
     if ( !jQuery.isFunction( fn ) ) {
         return undefined;
     }
     // 模拟上下文绑定
     args = slice.call( arguments, 2 );     // 截取fn所需要的参数
     proxy = function() {
         return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
     };
     // 为唯一的句柄设置guid,这个guid应该与原理fn的guid一样,使得它可以被移除
     proxy.guid = fn.guid = fn.guid || jQuery.guid++;
     return proxy;
 },
  // 新建一个时间对象并返回
 now: function() {
     return +( new Date() );
 },
 // jQuery不会在内核中使用,但其他项目会将一些属性设置到support中
 support: support
 });
- jQuery.extend在进行扩展的时候,是使用到了深拷贝,这是教科书式的用法,对Object和Array对象进行递归合并,将其中所有的属性都作拷贝。这样做的原因是在JavaScript里,对右值为Object和Array的赋值操作是执行引用而非拷贝,因此必须遍历Object和Array的属性以实现深拷贝;
- 方法重载的技巧再次出现,如jQuery.proxy。重载的实现实际上要对参数类型、参数数量进行判断,以进行不同的处理;
- 为了绑定函数方法的上下文环境,我们可以使用jQuery.proxy,而.proxy的实现使用到了function.apply(conext, args);
- jQuery.grep的实现也是比较巧妙,添加一个形参invert来进行反向选择,即可以利用一个callback作出双向选择,这也是一个简单而巧妙的技巧。
jQuery 源码分析6: jQuery 基本静态方法(二)的更多相关文章
- jQuery源码分析之=>jQuery的定义
		最近写前段的代码比较多,jQuery是用的最多的一个对象,但是之前几次看了源码,都没搞清楚jQuery是怎么定义的,今天终于看明白怎么回事了.记录下来,算是一个新的开始吧. (文中源码都是jQuery ... 
- jQuery 源码分析4: jQuery.extend
		jQuery.extend是jQuery最重要的方法之一,下面看看jQuery是怎样实现扩展操作的 // 如果传入一个对象,这个对象的属性会被添加到jQuery对象中 // 如果传入两个或多个对象,所 ... 
- jQuery 源码分析3: jQuery.fn/ jQuery.prototype
		// 建立方法实例,提高方法访问的速度(避免在原型链上搜索) var deletedIds = []; var slice = deletedIds.slice; var concat = delet ... 
- jquery源码分析(七)——事件模块 event(二)
		上一章节探讨了事件的一些概念,接下来看下jQuery的事件模块. jQuery对事件的绑定分别有几个API:.bind()/.live()/.delegate()/.on()/click(), 不管是 ... 
- jQuery 源码分析5: jQuery 基本静态方法(一)
		jQuery在初始化过程中会为自己扩展一些基本的静态方法和属性,以下是jQuery 1.11.3版本 239 ~ 564行间所扩展的静态属性和方法 jQuery.extend({ // 为每个jQ ... 
- jQuery 源码分析2: jQuery.fn.init
		//jQuery.fn.intit 中使用到的外部变量: // 判断是否为HTML标签或#id rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w ... 
- 六.jQuery源码分析之jQuery原型属性和方法
		97 jQuery.fn = jQuery.prototype = { 98 constructor: jQuery, 99 init: function( selector, context, ro ... 
- jQuery源码分析系列
		声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ... 
- [转] jQuery源码分析-如何做jQuery源码分析
		jQuery源码分析系列(持续更新) jQuery的源码有些晦涩难懂,本文分享一些我看源码的方法,每一个模块我基本按照这样的顺序去学习. 当我读到难度的书或者源码时,会和<如何阅读一本书> ... 
随机推荐
- Everything
			Everything,windows下做好用的搜索工具,速度特别快!下载地址:http://www.voidtools.com/ 快速下载地址:http://files.cnblogs.com/fil ... 
- bzoj 1064【noi2008】假面舞会
			题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1064 给一个有向图染色,每个点的后继必须相同,问至少&至多有多少种染色方案 sol: ... 
- 用hdfs存储海量的视频数据的设计思路
			用hdfs存储海量的视频数据 存储海量的视频数据,主要考虑两个因素:如何接收视频数据和如何存储视频数据. 我们要根据数据block在集群上的位置分配计算量,要充分利用带宽的优势. 1.接收视频数据 将 ... 
- Android开发之有效获取状态栏(StatusBar)高度
			获取状态栏高度 一.传统方式:有时获取为0,解决方法看 二 1 2 3 4 代码 Rect frame = new Rect(); getWindow().getDecorView().getWin ... 
- 通过Wifi调试Android应用
			国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ... 
- 使用Go语言两三事
			使用Go语言两三事,在网上看到的总结的很不错哦,转自http://www.cnblogs.com/sevenyuan/archive/2013/02/27/2935887.html 一.channel ... 
- UNIX标准化及实现之标准之间的冲突
			就整体而言,这些不同的标准之间配合得相当好.但是我们也很关注它们之间的差别,特别是ISO C标准和POSIX.1之间的差别. ISO C定义了函数clock,它返回进程使用的CPU时间,返回值类型是c ... 
- Android_Handler
			xml文件: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:t ... 
- 对setTimeout()第一个参数是字串的深入理解以及eval函数的理解
			<script language="javascript" type="text/javascript"> var a=1; setTimeout( ... 
- 使用AndroidScreenSlidePager开源库
			一.下载地址 https://github.com/LyndonChin/AndroidScreenSlidePager 点击右侧的Download ZIp按钮进行下载.然后解压缩到本地. 二.使用方 ... 
