50-解决方案
5.12.2 解决方案
使用
while或者do...while循环会更快吗?可能不会。可以将前一个循环改写为: 或: 但是两种写法都不比更易读的for循环快。
有关for..in循环的警告 决不要将
for..in循环用于jQuery对象或者任何类型数组的循环读取中。如果数组有任何自定义属性或者方法,它们将和数字型数组元素一起循环读取。例如,下面的代码枚举一个DOM元素——文档主体(i=0): 下面的代码似乎也做同样的工作,但是除了[0]元素以外,它还会列举所有jQuery方法,如show和css: 这时应该用前面列举的数组循环来完成。 如果你的页面上有任何代码修改了Object.prototype,用附加的方法或者属性扩展所有对象,那么即使是for..in循环的“安全”用法也可能遇到问题。除了你想要的内容之外,循环还会列举那些方法或者属性。 我们非常反对扩展Object.prototype,因为它会破坏很多代码。实际上,至少在jQuery 1.3.2中,它就因为导致each()列举添加的方法或者属性而破坏了jQuery本身。如果你的代码必须工作于这种环境,就必须对所有的循环多加注意,如测试每个对象属性的hasOwnProperty()方法。遗憾的是,因为这些额外的测试会降低代码运行速度,所以你必须在速度和健壮性之间做出选择。
使用 for 循环代替 .each() 。在循环读取数组的方法中,下面的循环是难以战胜的:
for( var item, i = −1; item = array[++i] ) {
// 处理item
}
var i = −1,n = array.length;
while(++i < n){
var item = array[i];
// 处理item
}
$('body').each(function(i){ console.log(i);});
但是这里有个例外:这种循环只能在数组没有“假”元素时才能正常工作,也就是说,数组里不能有值为 undefined 、 null 、 false 、 0 或者“”的元素。尽管有这样的限制,这种循环在许多常见情况下还是有用的,例如,在jQuery对象中的循环。只是,一定要将对象缓存在变量中:
var $items = $('.lotsOfElements');
for( var item, i = −1; item = $item[++i] ) {
// 处理item (DOM节点)
}
var i = 0,n = array.length;
if(i < n)do {
var item = array[i];
// 处理item
}
while(++i < n);
for(var i in $('body'))console.log(i);// BAD
像秘诀5.11那样,将对象数组包含在JSON数据中也是常见的:
{
"names": [
{
// ...
"zip": "48786"
},
//重复1000个名字
]
}
如果你知道组成 names 数组元素的对象都不为null,使用这种快速循环就很安全了。
为了编写一个更通用的、可以用于任何数组的循环,可以使用你在许多地方都能看到的经典循环:
for( var i = 0; i < array.length; i++ ) {
var item = array[i];
//处理item
}
还可以在三个方面改进这种循环:
- 缓存数组长度。
- 使用
++i, 在某些浏览器中它快于i++。 - 合并循环变量的测试和递增,减少一次名称查找。
结果如下:
for( var i = −1, n = array.length; ++i < n; ) {
var item = array[i];
// 处理item
}
注意
可以使用 for..in 循环读取对象(不是数组):
for( var key in object ) {
var item = object[key];
// 处理item
}