大家都知道在JavaScript中提供了兩種方式迭代物件:
一、for循環
不足:
在於每次循環的時候數組的長度都要去取得;
終止條件要明確;
在for循環中,你可以循環取得陣列或是陣列類似物件的值,譬如arguments和HTMLCollection物件。通常的循環形式如下:
// 次佳的循环 for (var i = 0; i < myarray.length; i++) { // 使用myarray[i]做点什么 }
這種形式的循環的不足在於每次循環的時候數組的長度都要去獲取下。這回降低你的程式碼效能,尤其當myarray不是數組,而是HTMLCollection物件的時候。
HTMLCollections指的是DOM方法傳回的對象,例如:
document.getElementsByName()
document.getElementsByClassName()
document.getElementsByTagName()
還有其他一些HTMLCollections,這些是在DOM標準之前引進並且現在還在使用的。有:
document.images: 頁面上所有的圖片元素
document.links : 所有a標籤元素
document.forms : 所有表單
document.forms[0].elements : 頁面上第一個表單中的所有網域
集合的麻煩在於它們即時查詢基本文件(HTML頁面)。這意味著每次你訪問任何集合的長度,你要即時查詢DOM,而DOM操作一般都是比較昂貴的。
這就是為什麼當你循環取得值時,快取數組(或集合)的長度是比較好的形式,正如下面程式碼所顯示的:
for (var i = 0, max = myarray.length; i < max; i++) { // 使用myarray[i]做点什么 }
這樣,在這個循環過程中,你只檢索了一次長度值。
在所有瀏覽器下,循環取得內容時快取HTMLCollections的長度是更快的,2倍(Safari3)到190倍(IE7)之間。 //此資料看起來很老
注意到,當你明確想要修改循環中的集合的時候(例如,添加更多的DOM元素),你可能更喜歡長度更新而不是常數。
伴隨著單var形式,你可以把變數從循環中提出來,就像下面這樣:
function looper() { var i = 0, max, myarray = []; // ... for (i = 0, max = myarray.length; i < max; i++) { // 使用myarray[i]做点什么 } }
這種形式具有一致性的好處,因為你堅持了單一var形式。不足在於當重構程式碼的時候,複製和貼上整個循環有點困難。例如,你從一個函數複製了一個循環到另一個函數,你不得不去確定你能夠把i和max引入新的函數(如果在這裡沒有用的話,很有可能你要從原函數中把它們刪掉)。
最後一個需要對循環進行調整的是使用下面表達式之一來取代i 。
i = i + 1 i += 1
JSLint提示您這樣做,原因是 和–-促進了“過分棘手(excessive trickiness)”。如果你直接無視它,JSLint的plusplus選項會是false(預設是default)。
兩種變化的形式:
//第一种变化的形式: var i, myarray = []; for (i = myarray.length; i–-;) { // 使用myarray[i]做点什么 } //第二种使用while循环: var myarray = [], i = myarray.length; while (i–-) { // 使用myarray[i]做点什么 }
這些小的改進只體現在性能上,此外JSLint會對使用i–-加以抱怨。
二、for …in 迴圈—又稱為「枚舉」
for …in 迴圈常用來迭代物件的屬性或陣列的每個元素,for…in迴圈中的迴圈計數器是字串,而不是數字。它包含目前屬性的名稱或目前數組元素的索引。 下面直接上幾個例子:
當遍歷一個物件的時候,變數 i 也就是循環計數器 為 物件的屬性名稱 :
//使用for..in循环遍历对象属性 varperson={ name: "Admin", age: 21, address:"shandong" }; for(var i in person){ console.log(i); }
執行結果為:
名稱
age
address
當遍歷一個陣列的時候,變數 i 也就是循環計數器 為 目前陣列元素的索引 :
//使用for..in循环遍历数组 vararray = ["admin","manager","db"] for(vari in array){ console.log(i); }
執行結果:
0
1
2
但是,現在看來for .. in循環還挺好用啊,不過,別高興太早,看看下面的例子:
var array =["admin","manager","db"]; //给Array的原型添加一个name属性 Array.prototype.name= "zhangsan"; for(var i in array){ alert(array[i]); }
运行结果:
admin
manager
db
zhangsan
咦,奇观了,怎么平白无故的冒出来一个zhangsan
现在,再看看使用 for循环会怎样?
vararray = ["admin","manager","db"]; //给Array的原型添加一个name属性 Array.prototype.name = "zhangsan"; for(var i =0 ; i<array.length; i++){ alert(array[i]); };
运行结果:
admin
manager
db
哦, 现在明白了,for..in循环会把某个类型的原型(prototype)中方法与属性给遍历出来,所以这可能会导致代码中出现意外的错误。为了避免这个问题,我们可以使用对象的hasOwnProperty()方法来避免这个问题,如果对象的属性或方法是非继承的,那么hasOwnProperty() 方法返回true。即这里的检查不涉及从其他对象继承的属性和方法,只会检查在特定对象自身中直接创建的属性。
vararray = ["admin","manager","db"]; Array.prototype.name= "zhangshan"; for(var i in array){ //如果不是该对象自身直接创建的属性(也就是该属//性是原型中的属性),则跳过显示 if(array.hasOwnProperty(i)){ alert(array[i]); } }
运行结果:
admin
manager
db
另外一种使用hasOwnProperty()的形式是取消Object.prototype上的方法。像这样:
// 对象 var man = { hands: 2, legs: 2, heads: 1 }; for (var i in man) { if (Object.prototype.hasOwnProperty.call(man, i)) { // 过滤 console.log(i, ":", man[i]); } }
其好处在于在man对象重新定义hasOwnProperty情况下避免命名冲突。也避免了长属性查找对象的所有方法,你可以使用局部变量“缓存”它。
var i, hasOwn = Object.prototype.hasOwnProperty; for (i in man) { if (hasOwn.call(man, i)) { // 过滤 console.log(i, ":", man[i]); } }
严格来说,不使用hasOwnProperty()并不是一个错误。根据任务以及你对代码的自信程度,你可以跳过它以提高些许的循环速度。但是当你对当前对象内容(和其原型链)不确定的时候,添加hasOwnProperty()更加保险些。
格式化的变化(通不过JSLint)会直接忽略掉花括号,把if语句放到同一行上。其优点在于循环语句读起来就像一个完整的想法(每个元素都有一个自己的属性”X”,使用”X”干点什么):
// 警告: 通不过JSLint检测 var i, hasOwn = Object.prototype.hasOwnProperty; for (i in man) if (hasOwn.call(man, i)) { // 过滤 console.log(i, ":", man[i]); }
以上就是介绍了JavaScript提供的两种方式迭代对象:for循环和for...in循环,希望这篇文章对大家的学习有所帮助。