問題:js中定義的數(shù)組遍歷完成,最后會有一段亂碼,如下:
上面的數(shù)據(jù)正常顯示,但是最后會有一段亂碼。
原因:用for-in遍歷數(shù)組的時候最后會多遍歷一次,最后的一次在數(shù)組中不存在,所以造成了上面的問題。
簡單 for 循環(huán)
下面先來看看大家最常見的一種寫法:
var arr = [1, 2, 3];for(var i = 0; i < arr.length; i++) { console.log(arr[i]);}
當(dāng)數(shù)組長度在循環(huán)過程中不會改變時,我們應(yīng)將數(shù)組長度用變量存儲起來,這樣會獲得更好的效率,下面是改進的寫法:
var arr = [1, 2, 3];for(var i = 0, len = arr.length; i < len; i++) { console.log(arr[i]);}
for-in
通常情況下,我們可以用 for-in 來遍歷一遍數(shù)組的內(nèi)容,代碼如下:
var arr = [1, 2, 3];var index;for(index in arr) { console.log("arr[" + index + "] = " + arr[index]);}
一般情況下,運行結(jié)果如下:
arr[0] = 1arr[1] = 2arr[2] = 3
但這么做往往會出現(xiàn)問題。
for-in 的真相
for-in 循環(huán)遍歷的是對象的屬性,而不是數(shù)組的索引。因此, for-in 遍歷的對象便不局限于數(shù)組,還可以遍歷對象。例子如下:
var person = { fname: "san", lname: "zhang", age: 99};var info;for(info in person) { console.log("person[" + info + "] = " + person[info]);}
結(jié)果如下:
person[fname] = sanperson[lname] = zhangperson[age] = 99
需要注意的是, for-in 遍歷屬性的順序并不確定,即輸出的結(jié)果順序與屬性在對象中的順序無關(guān),也與屬性的字母順序無關(guān),與其他任何順序也無關(guān)。
現(xiàn)在,我們再回過頭來看看用 for-in 來循環(huán)數(shù)組的例子,我們修改一下前面遍歷數(shù)組的例子:
var arr = [1, 2, 3];arr.name = "Hello world";var index;for(index in arr) { console.log("arr[" + index + "] = " + arr[index]);}
運行結(jié)果是:
arr[0] = 1arr[1] = 2arr[2] = 3arr[name] = Hello world
我們看到 for-in 循環(huán)訪問了我們新增的 “name” 屬性,因為 for-in 遍歷了對象的所有屬性,而不僅僅是“索引”。同時需要注意的是,此處輸出的索引值,即 “0″、 “1″、 “2″不是 Number 類型的,而是 String 類型的,因為其就是作為屬性輸出,而不是索引。那是不是說不在我們的 Array 對象中添加新的屬性,我們就可以只輸出數(shù)組中的內(nèi)容了呢?答案是否定的。因為 for-in 不僅僅遍歷 array 自身的屬性,其還遍歷 array 原型鏈上的所有可枚舉的屬性。下面我們看個例子:
Array.prototype.fatherName = "Father";var arr = [1, 2, 3];arr.name = "Hello world";var index;for(index in arr) { console.log("arr[" + index + "] = " + arr[index]);}
運行結(jié)果是:
arr[0] = 1arr[1] = 2arr[2] = 3arr[name] = Hello worldarr[fatherName] = Father
寫到這里,我們可以發(fā)現(xiàn) for-in 并不適合用來遍歷 Array 中的元素,其更適合遍歷對象中的屬性,這也是其被創(chuàng)造出來的初衷。卻有一種情況例外,就是稀疏數(shù)組。考慮下面的例子:
var key;var arr = [];arr[0] = "a";arr[100] = "b";arr[10000] = "c";for(key in arr) { if(arr.hasOwnProperty(key) && /0$|[1-9]\d$/.test(key) && key <= 4294967294 ) { console.log(arr[key]); }}
for-in 只會遍歷存在的實體,上面的例子中, for-in 遍歷了3次(遍歷屬性分別為”0″、 “100″、 “10000″的元素,普通 for 循環(huán)則會遍歷 10001 次)。所以,只要處理得當(dāng), for-in 在遍歷 Array 中元素也能發(fā)揮巨大作用。
為了避免重復(fù)勞動,我們可以包裝一下上面的代碼:
function arrayHasOwnIndex(array, prop) { return array.hasOwnProperty(prop) && /0$|[1-9]\d$/.test(prop) && prop <= 4294967294; // 2^32 - 2}
使用示例如下:
for (var key in arr) { if (arrayHasOwnIndex(arr, key)) { console.log(arr[key]); }}
查詢結(jié)果如上,簡單的說就是for-in中的輸出是屬性類型,不僅僅是索引。他們的索引值不是我們想象的number類型,而是看到的string類型。
for..in循環(huán)會把某個類型的原型(prototype)中方法與屬性給遍歷出來,所以這可能會導(dǎo)致代碼中出現(xiàn)上述的問題。
解決辦法:
如果不是該對象自身直接創(chuàng)建的屬性(也就是該屬//性是原型中的屬性),則跳過顯示
if(!array.hasOwnProperty(i)){
continue;
}