就for循环VS for-in循环

这种模式的问题在于每次循环迭代的时候都要访问数据的长度。这样会使代码变慢,特别是当myarray不是数据,而是HTML容器对象时。

HTML容器是DOM方法返回的对象,如:
document.getElementsByName()
document.getElementsByClassName()
document.getElementsByTagName()
还有很多其他HTML容器,他们在DOM标准以前就引入了,并一直使用至今。包括(除此之外还有很多):
docuement.images
页面上所有的IMG元素。
document.links
页面的A元素
document.forms
所有的froms。
document.forms[0].elements
页面上第一个from内的所有字段

容器的麻烦在于他们在document(HTML页面)下是活动的查询。也就是说,每次访问任何容器的长度时,也就是在查询活动的DOM操作时非常耗时的。

这就是为什么好的for循环模式是将已经遍历过的数组(或容器)的长度缓存起来。如以下代码所示。
for (var i = 0; max = myarray.length; i++) {
//对myarray[i]进行处理
}
这种方式下,对长度的值只提取一次,但应用到整个循环中。

在所有的浏览器中,通过将HTML容器上需要遍历的次数缓存起来都会大大提高速度。其中在Safari 3中速度会提高两倍,而在Ie7种会提高170倍。
注意,当要在循环中修改容器时(例如新增一个DOM元素),需要修改容器的长度。
function looper() {
var i = 0,
max,
myarray = [];

//...

for (i = 0, max = myarray.length; i < max; i++) {
//处理myarray[i]
}
}

这种模式的好处在于一致性,因为他贯穿了单一变量的模式。至缺陷在于创建代码时粘贴和复制整个循环比较麻烦。例如,如果要从一个函数复制循环至另一个函数,必须确保能将i和max携带至新函数中(如果这几个量在原函数中不再需要,则很可能会删掉他们了)。

对于循环的最后一个改进是,用i++代替以下两种表达式:
i = i + 1;
i += 1;

JsJLint推荐这样做,原因++和--提倡“excessive trickiness”,如果不同意这种说法,
可以将JsLint操作的plusplus设成flase(默认为真)。

for 模式中的两个变量引出了一些细微操作,原因是:
1.使用了最少的变量(而非最多)
2.逐步渐至0,这样通常更快,因为同0比较比同数组的长度比较,或同非0数组比较更有效率。

第一个修改后的模式是:
var i, myarray = [];
//注意要添加;号,这个是省略了第三个参数而已
for (i = myarray.length; i--;) {
//处理myarray[i]
}

第二个使用while循环:
var myarray = [],
i = myarray.length;

while (i--) {
//处理myarray[i]
}

for-in循环

for-in 循环应该用来遍历非数组对象。使用for-in循环也被称为枚举(enumeration);
从技术上来说,也可以使用for-in循环来遍历数组 (因为JavaScript中,数组也是对象),但是不推荐用户这样使用,因为当该数组对象已经被自定义函数扩大后,这样做有可能会导致逻辑上的错误。因此推荐使用正常的for循环来处理数组,并使用for-in循环来处理对象。

请考虑如下例子:

//对象
var man = {
hands: 2,
legs: 2,
heads: 1
};
//代码的其他部分
//将一个方法添加到所有对象上
if (typeof Object.prototype.clone === "undefined") {
Object.prototype.clone = function() {};
}

在本例子中,使用文本定义了一个简单的名为man的对象。在man对象定义前面或者后面的其他位置,使用了一个名为clone()的所有的方法来增加Object的原型。该原型链式活动的,这也就意味着所有的对象都会自动获取针对新方法的访问。为了避免在枚举man的方法时枚举出clone()方法,需要调用hasOwnPorperty()函数来过滤该原型属性。如果不使用过滤函数来进行过滤,将会显示出clone(),这在大多数情况下是不希望得到的结果。
//1.
//for-in循环
for (var i in man) {
if (man.hasOwnProperty(i )) {
console.log(i, ":", man[i]);
}
}
/
hands: 2
legs: 2
heads: 1
/

//2.
//反模式:
//不使用hasOwnProperty()进行检查后使用for-in循环的结果
for (var i in man) {
console.log(i, ":", man[i]);
}

/
控制台中的结果
hands: 2
legs: 2
heads: 1
clone: function()
/

另外一种使用hasOwnPorperty()的模式是在Object.ptototype中调用该函数,如下所示:

for (var i in man) {
if (Object.prototype.hasOwnProperty.call(man, i )) { //过滤
console.log(i, ":", man[i]);
}
}

在使用hasOwnProperty对man对象进行精炼后,可以有效的避免命名冲突,也可以使用一个本地变量来缓存比较长的属性如下所示:

var i,
hasOwn = Object.prototype.hasOwnProperty;
for (i in man) {
if (hasOwn.call(man, i)) { //过滤
console.log(i, ":", man[i]);
}
}

你可能感兴趣的:(for循环)