如果是数字,Chrome 重新排序对象键是否正常/预期

IT技术 javascript json google-chrome javascript-objects
2021-03-17 04:17:02

我注意到某些用于评估电子商务网站的某些鞋码并将它们输出到屏幕上的代码在 Chrome 中弄乱了订单。

给定的 JSON 可以是:

{
  "7": ["9149", "9139", "10455", "17208"],
  "7.5": ["9140", "9150", "10456", "17209"],
  "8": ["2684", "9141", "10457", "17210"],
  "8.5": ["9142", "10444", "10458", "17211"],
  "9": ["2685", "9143", "10459", "17212"],
  "9.5": ["10443", "9144", "10460", "17213"]
}

...将大小减半。

在转换为对象并通过键进行迭代后,自然顺序得到尊重,结果如下:

7、7.5、8、8.5 等

但仅在 Chrome 中,“看起来”像整数的键总是首先从对象中出来,所以 for... in 循环的输出是:

7, 8, 9, 7.5, 8.5, 9.5 ...

Object.keys(sizes); // ["7", "8", "9", "7.5", "8.5", "9.5"]

这是测试用例:https : //jsfiddle.net/wcapc46L/1/

它只影响整数,似乎 Webkit/Blink 有一个优化,它更喜欢数字的对象属性,也许它与分支预测或其他什么有关。

如果使用任何字符作为对象键的前缀,则顺序不受影响并按预期工作 - FIFO

我想我记得读过关于对象的属性顺序没有保证的文章,但同时,这非常烦人,并且会导致单独为 chrome 用户修复它的大量工作。

有任何想法吗?这可能是一个可以修复的错误吗?

另外编辑,我现在发现这是 v8 错误跟踪器上的一个问题:

https://code.google.com/p/v8/issues/detail?id=164

看起来 Blink 不想解决这个问题,并且将仍然是唯一会这样做的浏览器。

更新任何哈希表优化 webkit/blink,现在已经进入 Gecko (FF 27.0.1) - https://jsfiddle.net/9Htmq/结果在7,8,9,7.5,8.5,9.5. _在键返回正确/预期的顺序之前应用

2017年更新人们仍然upvoting和编辑会这样-这似乎并不影响Map/ WeakMapSet等等(这表现在已更新的主要例子)

6个回答

这是 v8 处理关联数组的方式。一个已知问题问题 164,但它遵循规范,因此被标记为“按预期工作”。循环关联数组没有必需的顺序。

一个简单的解决方法是在数字值前面加上字母,例如:'size_7':['9149','9139']等。

该标准将在下一个 ECMAScript 规范中更改,迫使 [chrome] 开发人员对此进行更改。

保留顺序,因为所有其他浏览器都已经这样做了。
2021-04-27 04:17:02
更改支持 chrome 的当前实现还是支持保留定义顺序?
2021-04-29 04:17:02
“标准将在下一个 ECMAScript 规范中改变,迫使开发人员改变这一点。” 真的吗?这哪里有证据?最近的 ECMAScript 5 规范没有指定顺序。听起来它在最后一分钟掉了下来;谁说下次不会再发生?
2021-04-29 04:17:02
好吧,愚蠢的雷西格先生,如果他依赖于此。依赖于非一致观察而不是指定的行为会导致糟糕的、不可靠的代码。
2021-05-09 04:17:02
它可能不是规范的一部分。我在 John Resig 的博客中读到了它。ejohn.org/blog/javascript-in-chrome
2021-05-19 04:17:02

当用作索引/属性名称时,Chrome 似乎将整数字符串视为数字类型。

我认为依靠 Javascript 实现来保留在某些情况下是对象属性的顺序,而在其他情况下(当然是使用 chrome)数组索引,这显然是一种不安全的方法,枚举的顺序可能没有在规范中定义. 我建议向 JSON 添加一个指示排序顺序的附加属性:

{
    "7":{"sortOrder":1,"data":["9149","9139","10455","17208"]},
    "7.5":{"sortOrder":2,"data":["9140","9150","10456","17209"]}
    //etc
}
可以工作 - 我可以应用一个过滤器,在循环时检查 sortOrder 属性,并相应地在 DOM 中注入元素。
2021-05-16 04:17:02

在迭代对象的属性时,ECMAScript 规范中将顺序指定为未定义,并且不应依赖您在某些环境中观察到的任何顺序。如果您需要订购,请使用Array.

它们被视为字符串,因为它们字符串。我最好的建议是在所有键中使用相同的“精度”。

{
  "7.0": ["9149", "9139", "10455", "17208"],
  "7.5": ["9140", "9150", "10456", "17209"],
  "8.0": ["2684", "9141", "10457", "17210"],
  "8.5": ["9142", "10444", "10458", "17211"],
  "9.0": ["2685", "9143", "10459", "17212"],
  "9.5": ["10443", "9144", "10460", "17213"]
}

因此,“8.0”而不是“8”等。

即使那样,也不能保证,但它们更有可能以相同的顺序出现。

为了更好地保证,请根据键执行排序,将值按排序顺序放入数组中。

遗憾的是,即使这适用于测试用例,这也不是实现的选项。尺码有多种选择,例如“S、M、L、XL、XXL”或“44,44.5,44.5”或“一种尺码”等,由商家根据每个产品定义。对 MYSQL 的输出进行排序涉及大量逻辑,因此它以正确的顺序而不是作为字符串到达​​——它涵盖了大约 40 个按偏好顺序预定义的独立大小。
2021-05-12 04:17:02

我不认为你可以称之为错误。就像您自己说的那样,对于对象的属性如何排序没有任何保证。

这不是答案。
2021-04-27 04:17:02