当前位置: 代码迷 >> Web前端 >> jQuery源码历代记二
  详细解决方案

jQuery源码历代记二

热度:53   发布时间:2012-07-19 16:02:19.0
jQuery源码历代记2

jQuery源码历代记1传送门?http://adamed.iteye.com/blog/1426963

?

前面详述了jQuery构造器中size和get的源码。

下面介绍下一个构造器中的方法each:

?

each : function( fn , args ) {
        return jQuery.each( this , fn , args );
}

?从源码中可以看出该方法就是直接调用jQuery工具方法each。

?

我们先简单看下这个方法(jQuery工具方法后在后面专门篇章进行详解,但由于jQuery.each()在很多地方使用到,所以再此先对其进行详解):

?

each : function( obj , fn , args ) {
        if ( obj.length == undefined ){
                for ( var i in obj ){
                        fn.apply( obj[ i ] , args || [ i , obj[ i ] ] );
                }
        }else{
                for ( var i = 0; i < obj.length; i++ ){
                        fn.apply( obj[ i ] , args || [ i , obj[ i ] ] );
                 }
          }
          return obj;
}

?这段代码很简洁,作用也很明显就是对obj集合中的每一个对象执行fn方法。

?

我们先看一下API中对jQuery.each(collection, callback(indexInArray, valueOfElement) )方法的描述:

?

Description: A generic iterator function, which can be used to seamlessly iterate over both objects and arrays. Arrays and array-like objects with a length property (such as a function's arguments object) are iterated by numeric index, from 0 to length-1. Other objects are iterated via their named properties. 
?

?

简单翻译一下:这是一个通用的迭代函数,它可以用来无缝迭代数组及对象。数组以及带有length属性这样的准数组对象(例如function中的arguments对象)是通过索引数值进行迭代的(从0到length-1)。其他对象是通过他们的属性名进行迭代的。

?

前面已经说过了,理解一个function设计原理先看它的使用方法。

?

对于jQuery.each()的实现源码的理解要从这个方法的使用开始入手,还是看API:

?

如果jQuery.each()方法的第一个参数是一个数组,则回调function的第一个参数是数组的索引。

?

$.each([52, 97], function(index, value) { 
  alert(index + ': ' + value); 
});//得到结果:0:52    1:97 

?

?若jQuery.each()方法的第一个参数传递的是Js对象(类似于JSON对象)则回调function的第一个参数是对象的属性名:

?

var map = {'flammable': 'inflammable','duh': 'no duh'};
$.each(map, function(key, value) {alert(key + ': ' + value);});
//得到结果:flammable:inflammable    duh:no duh

?PS:我们可以通过在回调函数中return false;来结束each方法的循环过程。return 任何非false的值均相当于执行continue,立刻进入下一个循环执行的过程。(1.2以后的版本的功能,参考下面的源码)

?

好了,明白了使用方法以后我们看下jQuery构造器的each方法中最最关键也是最可能不明白的一句代码:

fn.apply( obj[ i ] , args || [ i , obj[ i ] ] );

为了容易理解,我们拆分下API源码并举例:

?

var tempFunction = function(index, value) { alert(index + ': ' + value); };

$.each([52, 97], tempFunction);

?

调用each方法时执行的是:

? ?for ( var i in obj ){ fn.apply( obj[ i ] , args || [ i , obj[ i ] ] ); }

我们以第一次迭代为例,i=0 ?obj为[52, 97],obj[i]为52(注意这里是1个对象)

?

循环体执行时相当于tempFunction.apply(52,[0,52]) 也就是相当于执行 52.tempFunction(0,52)。所以在tempFunction中获取this时拿到的是52.

?

参考API中的描述:

?

?

Description:  In the case of an array, the callback is passed an array index and a corresponding array value each time. (The value can also be accessed through the this keyword, but Javascript will always wrap the this value as an Object even if it is a simple string or number value.) The method returns its first argument, the object that was iterated.
?

?

?简单翻译就是例子中的52在调用tempFunction时先被封装成了Object。(^_^翻译的简单吧。)

?//********************************我是成长的分界线*****************************

jQuery的each方法在jQuery 1.2以后实现方式重构为(为了理解方便我添加了一些大括号):

?

?

each: function( object, callback, args ) {
     var name, i = 0, length = object.length;
     if ( args ) {
     //*****这里省略了一些代码******
     } else {
         if ( length == undefined ) {
              for ( name in object ){
                  if ( callback.
                     call( object[ name ], name, object[ name ] ) === false ){
                       break;
                 }
             }
        } else{
          for ( var value = object[0]; i < length &&
                               callback.call( value, i, value ) !== false; 
                               value = object[++i] ){
                   //do nothing
           }
        }
        return object;
}
?

?

其实只是把apply改成call了,数组for循环时把执行那个地方放在判断区了。。核心思想没啥变化。。

?//*******************************这是传送门分割线******************************

我们回到jQuery 1.0构造器each方法这边来。

通过return jQuery.each( this , fn , args );我们看出来jQuery对象的each只是迭代jQuery对象本身的各个属性。

?

?

  相关解决方案