雖然在 JavaScript 中數(shù)組是對象,但是沒有好的理由去使用 for in 循環(huán)遍歷數(shù)組。
相反,有一些好的理由不去使用 for in 遍歷數(shù)組。
注意: JavaScript 中數(shù)組不是 關(guān)聯(lián)數(shù)組。 JavaScript 中只有對象來管理鍵值的對應(yīng)關(guān)系。但是關(guān)聯(lián)數(shù)組是保持順序的,而對象不是。
由于 for in 循環(huán)會枚舉原型鏈上的所有屬性,唯一過濾這些屬性的方式是使用 hasOwnProperty函數(shù),
因此會比普通的 for 循環(huán)慢上好多倍。
為了達(dá)到遍歷數(shù)組的最佳性能,推薦使用經(jīng)典的 for 循環(huán)。
var list = [1, 2, 3, 4, 5, ...... 100000000];
for(var i = 0, l = list.length; i < l; i++) {
console.log(list[i]);
}
上面代碼有一個處理,就是通過 l = list.length 來緩存數(shù)組的長度。
雖然 length 是數(shù)組的一個屬性,但是在每次循環(huán)中訪問它還是有性能開銷。
可能最新的 JavaScript 引擎在這點上做了優(yōu)化,但是我們沒法保證自己的代碼是否運行在這些最近的引擎之上。
實際上,不使用緩存數(shù)組長度的方式比緩存版本要慢很多。
length 屬性的 getter 方式會簡單的返回數(shù)組的長度,而 setter 方式會截斷數(shù)組。
var foo = [1, 2, 3, 4, 5, 6];
foo.length = 3;
foo; // [1, 2, 3]
foo.length = 6;
foo; // [1, 2, 3]
譯者注:
在 Firebug 中查看此時 foo 的值是: [1, 2, 3, undefined, undefined, undefined]
但是這個結(jié)果并不準(zhǔn)確,如果你在 Chrome 的控制臺查看 foo 的結(jié)果,你會發(fā)現(xiàn)是這樣的: [1, 2, 3]
因為在 JavaScript 中 undefined 是一個變量,注意是變量不是關(guān)鍵字,因此上面兩個結(jié)果的意義是完全不相同的。
// 譯者注:為了驗證,我們來執(zhí)行下面代碼,看序號 5 是否存在于 foo 中。
5 in foo; // 不管在 Firebug 或者 Chrome 都返回 false
foo[5] = undefined;
5 in foo; // 不管在 Firebug 或者 Chrome 都返回 true
為 length 設(shè)置一個更小的值會截斷數(shù)組,但是增大 length 屬性值不會對數(shù)組產(chǎn)生影響。
為了更好的性能,推薦使用普通的 for 循環(huán)并緩存數(shù)組的 length 屬性。
使用 for in 遍歷數(shù)組被認(rèn)為是不好的代碼習(xí)慣并傾向于產(chǎn)生錯誤和導(dǎo)致性能問題。