问题重现

需求是要获取一个车型列表,并且输出到页面上按年份排序,故而接口提供的对象简化如下

let obj = {  '2018': {modelCode: "204313",modelName: "2018款 Vanquish 6.0L S Coupe"},'2017': {modelCode: "202479",modelName: "2017款 Rapide 6.0L AMR"},'2013': {modelCode: "139705",modelName: "2013款  Rapide  6.0L S"}
}console.log(obj)
// {2013: {…}, 2017: {…}, 2018: {…}}

??? 为什么 2013 在前面了,用户肯定希望先看到新的车型的,这不科学!

解释

查阅了 ECMA-262 3rd edition ,如下文 It is an unordered collection of properties 就说到 ES3 标准的对象不排序,插入是啥顺序,遍历就是啥顺序

An object is a member of the type Object. It is an unordered collection of properties each of which contains a primitive value, object, or function. A function stored in a property of an object is called a method.

而我查阅了 ECMA-262 5.1 edition ,如下文,读者们应该留意到了少了 unordered collection 的描述。并且之后的 ES 版本对对象的描述都是如此。

an object is a member of the remaining built-in type Object; and a function is a callable object. A function that is associated with an object via a property is a method.

故此,我能得出结论 Chrome 等新版浏览器 js 引擎遵循的是新版 ECMA-262 5th。因此,使用 for-in 语句遍历对象属性时遍历书序并非属性构建顺序。而 IE6、7、8 等旧版本浏览器的 js 解析引擎遵循的是较老的 ECMA-262 3rd,属性遍历顺序由属性构建的顺序决定。

故此 Chrome 的 js 引擎遍历对象属性时会遵循一个规律:

它们会先提取所有 key 的 parseFloat 值为非负整数的属性,然后根据数字顺序对属性排序首先遍历出来,然后按照对象定义的顺序遍历余下的所有属性。

猜想

按照上面的解释,那么我来一个例子

let obj = {  'b': 'testb','a': 'testa','1': 'test1','测': 'test测','2': 'test2'
}console.log(Object.keys(obj));// [1, 2, 'b', 'a', '测']

果然会把 '1' 和 '2' 这种能被 parseFloat 转化为正整数的提到前面并且按照升序排

而 'a' 和 '测' 没法转为整数那就排在 '1'、'2' 后并按照构建时的顺序拍

解决问题

回到问题,对象既然不能保证其顺序,那么使用数组来进行遍历吧。

当然业务中如果需要查某个年份的车型,而不想要每次都遍历一遍的来找的话。可以维护两份数据。一份数组,用于遍历输出,一份对象,用于查。

补充

直到最近在极客时间翻阅到李兵老师的 图解 Google V8 的第三节 "V8采用了哪些策略提升了对象属性的访问速度?" 时,我终于发现了更深层次的解释。

借下图说法:V8 里的对象其实维护两个属性,会把数字放入线性的 elements 属性中,并按照顺序存放。会把非数字的属性放入 properties 中,不会排序,顺便说一句它可能是线性结构,取决于属性数量的多少。寻找属性时先 elements 而后在 properties。

为什么 JS 对象内部属性遍历的顺序乱了相关推荐

  1. 遍历和添加json对象的属性 和 遍历普通js对象的属性

    1. 遍历 json 对象的属性 //定义json对象 var person= { name: 'zhangsan', pass: '123', fn: function(){ alert(this. ...

  2. 使用变量的值作为JS对象的属性名,从而获取其对应的值

    使用变量的值作为JS对象的属性名,从而获取其对应的值 <script>var object={"a":1111,"b":2222};var para ...

  3. 基于js对象,操作属性、方法详解

    一,概述 在Java语言中,我们可以定义自己的类,并根据这些类创建对象来使用,在Javascript中,我们也可以定义自己的类,例如定义User类.Hashtable类等等. 目前在Javascrip ...

  4. JS对象 - Array属性方法汇总

    属性名 描述 prototype 为对象添加属性.方法 constructor 返回数组对象引用 length 返回数组元素数目 方法名 描述 返回 更改原数组 concat() 连接多个数组 连接后 ...

  5. python魔法属性_查看对象内部属性的名称和值,Python“魔法”属性__dict__的使用...

    我们知道,Python中"一切皆对象",Python是一门真正意义上面向对象的编程语言.因此,如果对对象内部存储结构了解不深入,在学习Python的道路上是没有办法进阶的.今天,我 ...

  6. php 获取js对象的属性值,js获取对象,数组所有属性键值(key)和对应值(value)的方法示例...

    本文实例讲述了js获取对象,数组所有属性键值(key)和对应值(value)的方法.分享给大家供大家参考,具体如下: var values=function(object) { var values ...

  7. JS对象的属性名规则

    /* * 使用对象字面量,可以在创建对象时,直接指定对象中的属性 * 语法:{属性名:属性值,属性名:属性值-} * 对象字面量的属性名可以加引号也可以不加,建议不加, * 如果要使用一些特殊的名字, ...

  8. 给JS对象添加属性和方法

    方式一:在定义对象时,直接添加属性和方法 function Person(name,age) {this.name = name;this.age = age;this.say = function( ...

  9. Js 对象添加属性

    var arr = new Array(); arr[0] = jQuery("#data1").val(); var obj = {}; obj.y='abc'; arr.pus ...

最新文章

  1. C++知识点53——虚继承
  2. Linux Malloc分析-从用户空间到内核空间
  3. Android之build.gradle配置签名
  4. 最强鸿蒙系统txt_鸿蒙系统升级时间确认,哪些手机有望成为首批“宠儿”?
  5. CSS之media Query
  6. 【转】VTK与Qt整合的示例
  7. 【LeetCode笔记】48. 旋转图像(Java、矩阵、偏数学、原地算法)
  8. 补码到底是个什么东西
  9. java基础知识回顾之---java String final类普通方法的应用之“按照字节截取字符串”...
  10. 摄像机标定之四大坐标系之间转换关系详解
  11. STM32 串口程序下载
  12. 项目管理师证怎么考?报考条件有哪些?
  13. 2020中南大学计算机学院考研初试成绩,中南大学2020考研复试分数线已公布
  14. Modbus设备通过边缘网关接入阿里云IoT平台
  15. 威纶通屏,标准程序范本非常漂亮都是重新做的素材,可以省去很多时间就能做出好看的界面
  16. Nexus私服(三)
  17. 电信4g网络问题及恢复方案
  18. Element快速入门
  19. 淘宝天猫如何导入数据包批量上传宝贝的方法
  20. MySQL读已提交有间隙锁吗_mysql中的幻读与间隙锁

热门文章

  1. Compose 实现手写春联效果
  2. Python中self用法详解
  3. Kafka创建Topic的两种方式
  4. 【数学】SSL_1335 蛋糕切割
  5. vue-2.5.16.js:597 [Vue warn]: Unknown custom element: ocean - did you register the component corre
  6. 新浪微博桌面客户端 v3.0.5.35466 官方PC版
  7. DataToExcel
  8. QQ在线代码,MSN在线代码,雅虎通在线代码,阿里旺旺在线代码
  9. PHP getimagesize(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL rou
  10. 【ppt制作软件】Focusky教程 | 怎样实现表格的行列转换?