27-讨论
5.6.3 讨论
jQuery的 .each() 方法不是什么高技术。实际上,如果截取jQuery 1.3.2的实现在大部分典型使用(在jQuery对象中循环)中的实际代码,就会发现它只是一个相当简单的循环:
jQuery.each = function( object, callback ) {
var value, i = 0, length = object.length;
for(
value = object[0];
i < length && callback.call( value, i, value ) !== false;
value = object[++i]
) {}
return object;
};
each() 函数还可以用更熟悉的方法编写:
jQuery.each = function( object, callback ) {
for(
var i = 0, length = object.length;
i < length;
++i
) {
var value = object[i];
if( callback.call( value, i, value ) === false )
break;
}
return object;
};
我们可以编写类似的函数,以其他实用的方式循环读取数组或者jQuery对象。比 .slowEach() 更简单的一个例子是以逆序循环读取jQuery对象:
//以相反的顺序循环读取数组或者jQuery对象
jQuery.reverseEach = function( object, callback ) {
for( var value, i = object.length; --i >= 0; ) {
var value = object[i];
console.log( i, value );
if( callback.call( value, i, value ) === false )
break;
}
};
//以相反的顺序循环读取"this"(一个jQuery对象)
jQuery.fn.reverseEach = function( callback ) {
jQuery.reverseEach( this, callback );
return this;
};
上面的代码并不试图处理 .each() 所处理的所有情况,只适用于典型jQuery代码的常规情况。
有趣的是,自定义迭代器可以完全不使用循环。 .reverseEach() 和标准的 .each() 都使用比较常规的循环,但是在 .slowEach() 中没有明确的JavaScript循环。为什么会这样?如何在不使用循环的情况下读取所有元素?
Web浏览器中的JavaScript没有在许多语言中都能找到的 sleep() 函数,所以不能这样暂停脚本的执行:
doSomething();
sleep( 1000 );
doSomethingLater();
作为替代,和JavaScript中的任何异步活动一样, setTimeout() 函数有一个回调参数,每隔一段时间就调用回调函数。 .slowEach() 方法在 setTimeout() 回调函数中递增“循环”变量 i ,利用闭包在两次“循环”之间保留变量值。(闭包的讨论参见秘诀5.2。)
和 .each() 一样, .slowEach() 直接在jQuery对象或者数组上操作,所以完成循环之前对数组的任何更改都会影响循环。和 .each() 不同的是, .slowEach() 是异步的(对回调函数的调用发生在 .slowEach() 返回之后), 所以如果在 .slowEach() 返回之后、回调之前改变jQuery对象或其元素,这也会影响到循环。