[Effective JavaScript 笔记]第46条:使用数组而不要使用字典来存储有序集合
Posted 脚后跟着猫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Effective JavaScript 笔记]第46条:使用数组而不要使用字典来存储有序集合相关的知识,希望对你有一定的参考价值。
对象属性无序性
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循环来枚举对象属性应当与顺序无关
-
如果聚集运算字典中的数据,确保聚集操作与顺序无关
-
使用数组而不是字典来存储有序集合
以上是关于[Effective JavaScript 笔记]第46条:使用数组而不要使用字典来存储有序集合的主要内容,如果未能解决你的问题,请参考以下文章
[Effective JavaScript 笔记] 第12条:理解变量声明提升
[Effective JavaScript 笔记]第15条:当心局部块函数声明笨拙的作用域
[Effective JavaScript 笔记]第48条:避免在枚举期间修改对象
[Effective JavaScript 笔记] 第14条:当心命名函数表达式笨拙的作用域