jquery对象的数组特性

本文深入探讨了jQuery中对象的数组特性实现原理,包括如何利用类数组对象存储DOM元素、实现数组方法,以及jQuery提供的get、eq、index等实用方法。
  1. 2.3、jquery对象的数组特性   
  2. 从上面一小节可以看出jquery构建函数完成了查找或转换或其它的功能,其结果就是找到元素,查找,转找不过是方式而已。找到元素就得找个地方去存储起来。这个地方是就是这一节要分析的。   
  3. 存储有序数据的地方(集合)在JS中最好的当然是数组。那么又如何在jQuery内面实现数组呢?可以采用如下的方式:   
  4. jQuery.fn.prototype=new Array();   
  5. 在上一节中的this.setArray(arr)函数中加上   
  6.   Array.apply(this,arr);   
  7. 如果还要完美一点,就加上:   
  8. jQuery.fn.prototype.constructor=jQuery。   
  9. 这样我们继承了数组的所有特性,又可以在Jquery对象进行数组的功能扩展。但是jQuery并没有这样采用继承Array而实现这个内部的集合。它采用了Array-Like的对象的实现(见JavaScript: The Definitive Guide, 5th Edition7.8节)。   
  10. 类数组的对象还是对象,只不过像数组。数组与对象其实是没有什么好大的区别的,有序和无序的集合是它们区别。这个区别反应在数组有的length属性。当添加元素它会自动加上相对的个数,当删除元素,它会自动减去相对的个数。   
  11. 看一下jQuery是怎么实现的:   
  12. // 第一种情况 Handle $(DOMElement)单个Dom 元素,忽略上下文   
  13.         if (selector.nodeType) {                                            ②   
  14.             this[0] = selector;   
  15.             this.length = 1;   
  16.             return this;   
  17.         }          
  18. 这是它的第一种实现方法,通过this[0]来直接设定第一个位置的Dom元素,同时设定length=1。这里我们可以看出对象与数组一样都是采用key/Value对的形式存在对象中。上面的Json形式为{0:aDom,length=1}。这里细细分析一下数组,数组是继承于对象。其[]的解释分析最终结果可以看作{}构的对象,对[]或数组的构建时会进行把index(如0.1,….)做为对象属性的key。把数组中的值做为其对应的value。同时改变length的值。这也就是说为什么本质上对象与数组没有多大的区别。在很多的源码中,如YUI中都采用对象的形式来构建多维数组。   
  19. this.setArray(jQuery.makeArray(selector));   
  20. 是其第二种实现的方法,上面实现是单个的元素,这个实现的多个元素的集合。它首先调用了jQuery.makeArray(selector)这个静态方法把集合(类数组)转换成数组。   
  21. 上面已经分析了数组和对象都可以采用obj.[attr]的形式来取得其key对应的value。对于集合或类数组,必须要求其实现length属性,有了length的长度,那么就从0~length-1的key属性中取得对应的value就可以了:   
  22. //把类数组的集合转换成数组,如果是单个元素就生成单个元素的数组。   
  23. makeArray: function( array ) {   
  24.     var ret = [];   
  25.     if( array != null ){    var i = array.length;   
  26.     //单个元素,但window, string、 function有 'length'的属性,加其它的判断   
  27.       if( i == null || array.split || array.setInterval || array.call )   
  28.           ret[0] = array;   
  29.       else//类数组的集合   
  30.           while( i )    ret[--i] = array[i];//Clone数组   
  31.      }   
  32. return ret;   
  33.     },   
  34. 生成了一个标准的数组,那么接下来setArray来干什么呢?   
  35. // 把array-like对象的元素全部push当前jquery对象。   
  36.     setArray : function(elems) {   
  37.         this.length = 0;//初始化长度,因为push会在原始的length++   
  38.         Array.prototype.push.apply(this, elems);   
  39.         return this;   
  40.     },   
  41. 这个调用了Array.prototype.push来自动修改length的属性值(当然是加入了元素)。由此可以推想到Array中众多的方法(如shift)都可以看作改变length的值在对象的key/value对中完成无序到有序或重新排序的工作。实际上Array等是采用C或C++来实现的。但是它构出的JS特性让我们可以这样去思考采用JavaScript的实现方式。   
  42. 上面的setArray(elems)函数只是会改变当前jQuery对象的集合,它会清除这个对象集合中以前的元素。但是有的时候我们想保存原来的集合中元素,同时也能就新传入的元素进行jquery对象的操作。它提供了pushStack函数来新建一个jQuery对象同时保存原来对象的引用。这样就可能在需要时用到自己所要的对象:   
  43.     pushStack : function(elems) {// 采用jQuery构建新对象,同时引用老对象。   
  44.         var ret = jQuery(elems);// 构建新的jquery对象   
  45.         ret.prevObject = this;// 保存老的对象的引用   
  46.         return ret;   
  47.     },   
  48. 返回的是新构建成的对象,有着jQuery对象的全部功能,同时还可以通过prevObject来访问原来的老对象。   
  49.   
  50. 构建了类数组,那么还得提供一些方法来操作这个集合,对于集合的操作无非就是定位元素,查找元素,复制(slice)和删除的操作(splice)等。jQuery还提供each,map的扩展。   
  51. 这些方法只和集合相关,与集合的元素的无关。jQuery提供了众多的和其中元素(DOM元素)相关的方法。   
  52.   
  53. 它提供了两个get元素的方法,get(index)和eq(index),不同是get取得是集合中的元素,而eq则是返回该元素的Clone。不会修改数组。其实可以直接通过[i]来代替get(i)。如果get没有参数则是获得全部元素。   
  54. // 取到本jquery对象的第几个Dom元素,无参数,代表全部的Dom元素   
  55.     get : function(num) {   
  56.         return num == undefined ? jQuery.makeArray(this) : this[num];   
  57.     },   
  58. // 获取第N个元素 。这个元素的位置是从0算起。   
  59.     eq : function(i) {   
  60.         return this.slice(i, +i + 1);   
  61.     },   
  62. 这两个函数就不用分析了。接下来看看如何实现在集合中定位元素:   
  63. / 找到elem在本jquery对象的位置(index)   
  64.     index : function(elem) {   
  65.         var ret = -1;   
  66.         return jQuery.inArray( // 如是jQuery对象就取第一个元素   
  67.                 elem && elem.jquery ? elem[0] : elem, this);   
  68.     },   
  69.   
  70. // 判断elem元素在array中的位置(index) 静态方法   
  71.     inArray : function(elem, array) {   
  72.             for (var i = 0, length = array.length;i < length; i++)   
  73.                 // Use === because on IE, window == document   
  74.                 if (array[i] === elem)   
  75.                     return i;   
  76.             return -1;   
  77.         },   
  78. inArray是jQuery的静态方法,而index是通过调用inArray来实现其定位的功能。Index的函数支持的参数可以是jQuery对象或Dom元素,而inArray则是实用方法,支持任何的元素。   
  79.   
  80. Jquery提供了如数组中slice复制的功能的方法,还提供类似concat的静态方法merge。Slice是通过Array中slice来实现的:   
  81.   / 代理数组的slice,同样的操作。   
  82.     slice : function() {   
  83.         return this.pushStack(Array.prototype.slice.apply(this, arguments));   
  84.     },   
  85. 它返回生成新的jQuery对象。这个对象的集合就是要复制后的集合。对于merge,它是静态方法,实现把第二个元素追加到第一个参数的数组中。   
  86. // 把second 元素追加到first的数组中。   
  87.         merge : function(first, second) {   
  88.      // We have to loop this way because IE & Opera overwrite the length   
  89.      // expando of getElementsByTagName   
  90.         var i = 0, elem, pos = first.length;   
  91.         // Also, we need to make sure that the correct elements are being   
  92.         // returned (IE returns comment nodes in a '*' query)   
  93.             if (jQuery.browser.msie) {   
  94.                 while (elem = second[i++])   
  95.                     if (elem.nodeType != 8)   
  96.                         first[pos++] = elem;   
  97.   
  98.             } else  
  99.                 while (elem = second[i++])   
  100.                     first[pos++] = elem;   
  101.   
  102.             return first;   
  103.         },   
  104. Jquery的each是对集合中每个元素都执行回调函数。   
  105.     // 当前jquery对象中每个元素都执行callback(index,elem)函数   
  106.     each : function(callback, args) {// 返回this   
  107.     // 其调用了jQuery的静态方法。prototype中的mothodize是解决这类问题的好方法   
  108.         return jQuery.each(this, callback, args);   
  109.     },     
  110. 它通过调用jQuery.each这个静态方法来完成功能的:   
  111. // 对object中的每个对象都执行callback函数进行处理。args仅仅内部用   
  112.      each : function(object, callback, args) {   
  113.             var name, i = 0, length = object.length;   
  114.             // 和else的处理差不多,args的传参代替object的属性值   
  115.             if (args) {   
  116.                 if (length == undefined) {   
  117.                     for (name in object)   
  118.                         if (callback.apply(object[name], args) === false)   
  119.                             break;   
  120.                 } else  
  121.                     for (;i < length;)   
  122.                         if (callback.apply(object[i++], args) === false)   
  123.                             break;   
  124.             } else {   
  125.                // 不是array-like的object,对每个属性进行callback函数的调用   
  126.     if (length == undefined) {   
  127.                 for (name in object)   
  128. if (callback.call(object[name], name, object[name]) === false)   
  129.                         break;   
  130.                    } else  
  131.                     // array-like object,采用数组的形式来处理   
  132.      for (var value = object[0];i < length   && callback.call(value, i, value) !== false; value = object[++i]) {}   
  133.             }   
  134.             return object;   
  135.         },   
  136. 该静态方法支持第一个参数的类数组(数组)或对象。是数组就对每个元素进行callback的操作。如果是对象,就是对每个属性值进行callback的操作。这个callback回调函数的格式如下:callback:function(index,value)。Index是索引号,value是数组的index对应的元素或对象的第index个处理的属性。如果使用args参数,那callback回调函数的格式如下:callback:function(args)。Args是给回调函数设定参数。再看一下jQuery对象的each。它的第二个参数args就是采用传入的args直接进行给callback设定参数,而不是默认提集合中index和对应的元素,但执行的次数还是集合的length次。   
  137.   
  138. Jquery的map是将一组元素转换成其他数组(通过回调函数返回值组成的)   // 将一组元素转换成其他数组 然后根据这个数组构建新的jquery对象。。   
  139.     map : function(callback) {   
  140.         return this.pushStack(jQuery.map(this, function(elem, i) {   
  141.             return callback.call(elem, i, elem);   
  142.         }));   
  143.     },   
  144. 这个函数首先通过jQuery.map(this, function(elem, i){}来把this的jQuery对象集合的每个元素当作回调函数的elem的参数传到回调函数中。而这个回调函数又执行实例方法的map : function(callback)中callback函数,也就是jQuery.map中的回调仅仅是传参代理的功能。jQuery.map通过代理的回调来取得转换而成的元素集合。   
  145. 接下来就是采用pushStack把这集合的元素构建成新的jQuery对象并返回,同时保存原jQuery对象的引用。   
  146. 看下Map的静态方法:   
  147.     // 返回对elems每个元素都进行操作的callback函数的返回值的集合。   
  148.         map : function(elems, callback) {   
  149.             var ret = [];              
  150.             for (var i = 0, length = elems.length;i < length; i++) {   
  151.                 var value = callback(elems[i], i);   
  152.                 if (value != null)//说明转换的集合的个数可能少于原来的集合   
  153.                     ret[ret.length] = value;   
  154.             }   
  155.             return ret.concat.apply([], ret);//采用array的concat实现   
  156.         }   
  157. Map的静态方法返回每个callback返回的元素组成的数组。  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值