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对象本身的各个属性。
?
?