對象屬性無序性 js對象是一個無序屬性集合。var obj={}; obj.a=10; obj.b=30; 屬性a和屬性b並沒有誰前誰後之說。for...in迴圈,先輸出哪個屬性都有可能。獲取和設置不同的屬性與順序無關,都會以大致相同的效率產生相同的結果。也就是說訪問屬性a和訪問屬性b,沒有哪個訪... ...
對象屬性無序性
js對象是一個無序屬性集合。
var obj={};
obj.a=10;
obj.b=30;
屬性a和屬性b並沒有誰前誰後之說。for...in迴圈,先輸出哪個屬性都有可能。
獲取和設置不同的屬性與順序無關,都會以大致相同的效率產生相同的結果。
也就是說訪問屬性a和訪問屬性b,沒有哪個訪問更快之說。ES標準並未規定屬性存儲的任何特定順序,甚至於枚舉對象也未涉及。for...in迴圈會挑選一定的順序來枚舉對象的屬性,標準允許js引擎自由選擇一個順序,它們的選擇會微妙地改變程式行為。
如要求一個對象表示一個從字元串到值的有序映射,創建一個有序的報表。
function report(highScores){
var res='';
var i=1;
for(var name in highScores){
res+=i+'. '+highScores[name].name+':'+highScores[name].points+'\n';
i++;
}
return res;
}
report([{name:'張三',points:1110111},
{name:'李四',points:1110102},
{name:'王五',points:1110911}]);
/*預期的結果
"1. 張三:1110111
2. 李四:1110102
3. 王五:1110911
"
*//*實際的結果 chrome,ff,ie
"1. 張三:1110111
2. 李四:1110102
3. 王五:1110911
"
*/
上面代碼在測試的幾個環境中表現順序和索引相符,但一些其它的環境可以選擇以不同的順序來存儲和枚舉對象的屬性,所以report有可能導致產生不同的字元串,得到不正確的報表。
程式對對象枚舉的順序依賴並不是顯式地。如果沒有在多個js環境中測試過你的代碼,那麼你的程式有可能因為for...in迴圈的不同輸出而導致改變。
依賴數據順序
如果對於數據結構中的條目順序有強依賴,那麼就優先考慮數組而不是字典。如上面的report函數如果接收的是一個數組而不是一個對象,那麼可以用for來迴圈,可以保證在所有環境順序都是一致正確的。
function report(highScores){
var res='';
for(var i=0,n=highScores.length;i < n;i++){
var score=highScores[i];
res+=(i+1)+'. '+score.name+':'+score.points+'\n';
}
return res;
}
report([{name:'張三',points:1110111},
{name:'李四',points:1110102},
{name:'王五',points:1110911}]);
//"1. 張三:1110111
2. 李四:1110102
3. 王五:1110911
"
通過接收一個對象數組,每個對象包含有name和points屬性,上面的代碼可以按0~highScores.length-1的順序遍歷所有的元素。
浮點型運算
假設有一個映射標題和等級的電影字典。
var ratings={
'Good Will Hunting':0.8,
'Mystic River':0.7,
'21':0.6,
'Doubt':0.9
};
浮點型算術運算的四捨五入會導致對計算順序依賴。詳細見《第2條:理解JavaScript的浮點數》。當組合未定義順序的枚舉時,可能會導致迴圈不可預知。
var total=0,count=0;
for(var key in ratings){
total+=ratings[key];
count++;
}
total/=count;
total;//chrome里:0.7499999999999999
在流行的js環境實際上使用不同的順序執行這個迴圈。一些環境按照下麵的順序來枚舉對象的key,得到下麵這個值。
(0.8+0.7+0.6+0.9)/4 //0.75
有些環境總是先枚舉潛在的數組索引,然後才是其他key。電影21是可以作為數組的索引的整數值,它首先被枚舉,得到下麵的結果。
(0.6+0.8+0.7+0.9)/4 //0.7499999999999999
可以看到上面的chrome就是先枚舉潛在的數組索引。
整數計算浮點型
對於浮點數的計算,可以把浮點數轉化為整數,然後再轉化回浮點數。整數的計算順序可以是任意順序的。所以對象的屬性值的列舉順序並不重要。代碼如下
(8+7+6+9)/4/10 //0.75
(6+8+7+9)/4/10 //0.75
提示
-
使用for...in迴圈來枚舉對象屬性應當與順序無關
-
如果聚集運算字典中的數據,確保聚集操作與順序無關
-
使用數組而不是字典來存儲有序集合