对象属性无序性

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. php利用递归函数实现无限级分类

    相信很多学php的很多小伙伴都会尝试做一个网上商城作为提升自己技术的一种途径.各种对商品分类,商品名之类的操作应该是得心应手,那么就可以尝试下无限级分类列表的制作了. 什么是无限级分类? 无限级分类是 ...

  2. 云计算之路-阿里云上:2014年6月12日16:14遭遇SLB故障

    这是今天遇到的第3次故障,故障是首先被园友发现的,访问园子出现来自SLB的错误提示:400 Bad Request - Powered by Tengine. 查看Windows性能监视器发现,在故障 ...

  3. Pell方程及其一般形式

    一.Pell方程 形如x^2-dy^2=1的不定方程叫做Pell方程,其中d为正整数,则易得当d是完全平方数的时候这方程无正整数解,所以下面讨论d不是完全平方数的情况. 设Pell方程的最小正整数解为 ...

  4. ssh开发流程

  5. Nginx 实现AJAX跨域请求

    在工作中遇到跨域请求的问题: AJAX从一个域请求另一个域会有跨域的问题.那么如何在nginx上实现ajax跨域请求呢?要在nginx上启用跨域请求,需要添加add_header Access-Con ...

  6. MVC的URL路由规则

    MVC的URL路由规则 Routing的作用:它首先是获取到View传过来的请求,并解析Url请求中Controller和Action以及数据,其次他将识别出来的数据传递给Controller的Act ...

  7. 『jQuery』.html(),.text()和.val()的概述及使用

    转自http://www.jb51.net/article/35867.htm 如何使用jQuery中的.html(),.text()和.val()三种方法,用于读取,修改元素的html结构,元素的文 ...

  8. codeforces 719B:Anatoly and Cockroaches

    Description Anatoly lives in the university dorm as many other students do. As you know, cockroaches ...

  9. 802.11协议帧格式、Wi-Fi连接交互过程、无线破解入门研究

    相关学习资料 Linux黑客大曝光: 第8章 无线网络 无线网络安全攻防实战进阶 无线网络安全 黑客大曝光 第2版 http://zh.wikipedia.org/wiki/IEEE_802.11 h ...

  10. Codeforces 46D Parking Lot

    传送门 D. Parking Lot time limit per test 2 seconds memory limit per test 256 megabytes input standard ...