对象属性无序性

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条:使用数组而不要使用字典来存储有序集合的更多相关文章

  1. [Effective JavaScript 笔记]第49条:数组迭代要优先使用for循环而不是for...in循环

    示例 下面代码中mean的输出值是多少? var scores=[98,74,85,77,93,100,89]; var total=0; for(var score in scores){ tota ...

  2. [Effective JavaScript 笔记]第52条:数组字面量优于数组构造函数

    js的优雅很大程序要归功于程序中常见的构造块(Object,Function及Array)的简明的字面量语法.字面量是一种表示数组的优雅方法. var a=[1,2,3,5,7,8]; 也可以使用构造 ...

  3. [Effective JavaScript 笔记]第5章:数组和字典--个人总结

    前言 这节里其实一直都在讨论对象这个在js中的万能的数据结构.对象可以表式为多种的形式,表示为字典和数组之间的区别.更多的我觉得这章讨论多的是一些对应实现功能的相关操作,有可能出现的bug以及如何避免 ...

  4. [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

    js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...

  5. [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符

    “1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...

  6. [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

    函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...

  7. [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

    js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...

  8. [Effective JavaScript 笔记]第58条:区分数组对象和类数组对象

    示例 设想有两个不同类的API.第一个是位向量:有序的位集合 var bits=new BitVector(); bits.enable(4); bits.enable([1,3,8,17]); bi ...

  9. [Effective JavaScript 笔记]第66条:使用计数器来执行并行操作

    第63条建议使用工具函数downloadAllAsync接收一个URL数组并下载所有文件,结果返回一个存储了文件内容的数组,每个URL对应一个字符串.downloadAllAsync并不只有清理嵌套回 ...

随机推荐

  1. α发布后的感想(组长作业)

    今天α发布后,组长作业,谈谈心得体会,谈谈哪些做的好的地方,哪些做的不好.耐撕团队组长因有事缺席,耐撕团队的α发布由齐同学来主持,所以这个作业由齐同学代理. 先谈谈耐撕团队在α发布会中齐同学认为做的好 ...

  2. WebView与JavaScript的交互

    目录: 一.整体思路 二.简单例子实现过程        1.打开项目的asset目录,创建新的文件test.html        2.补充html代码:添加供本地调用的js方法.调用本地方法的js ...

  3. UVA 540 stl

    Queues and Priority Queues are data structures which are known to most computer scientists. The Team ...

  4. Maven-环境快速搭建

    Jdk  1.5以上java开发环境. Eclipse IDE 一个. Maven 3.0.3下载地址: http://maven.apache.org/docs/3.0.3/release-note ...

  5. Throwable和Exception的区别

    Java语言要求java程序中(无论是谁写的代码)所有抛出(throw)的异常都必须是从Throwable派生而来.当然,实际的Java编程中,由于JDK平台已经为我们设计好了非常丰富和完整的异常对象 ...

  6. 【ZOJ 3502】Contest

    题 题意 n个问题,解决的顺序影响正确的概率,无论之前解决的问题是否答对,当前问题 j 答对概率为max{a[i][j]} (i为解决过的问题).求答对题目的最大期望和对应的答题顺序.T组测试,T ( ...

  7. POJ1065 Area

    Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 18499   Accepted: 5094 Description You ...

  8. CODEVS1995 || TYVJ1863 黑魔法师之门

    P1863 [Poetize I]黑魔法师之门 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 经过了16个工作日的紧张忙碌,未来的人类终于收集到了足够的能源 ...

  9. 轻量级应用开发之(06)Autolayout自动布局1

    一 什么是Autolayout Autolayout是一种“自动布局”技术,专门用来布局UI界面的. 自IOS7 (Xcode 5)开始,Autolayout的开发效率得到很大的提高. 苹果官方也推荐 ...

  10. 将ECSHOP会员注册页面的Email修改成非必填项

    将ECSHOP会员注册页面的Email修改成非必填项 ECSHOP教程/ ecshop教程网(www.ecshop119.com) 2011-07-29   有人说,在后台的 “会员注册项设置 ”里面 ...