30

我注意到某些代码会评估电子商务网站的某些鞋码并将它们输出到屏幕上,这会扰乱 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人们仍在投票和编辑它 - 它似乎不会影响Map/WeakMapSet(如更新的主要示例所示)

4

7 回答 7

24

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

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

该标准将在下一个 ECMAScript 规范中改变,迫使 [chrome] 开发人员改变这一点。

于 2010-07-06T14:06:54.590 回答
1

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

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

{
    "7":{"sortOrder":1,"data":["9149","9139","10455","17208"]},
    "7.5":{"sortOrder":2,"data":["9140","9150","10456","17209"]}
    //etc
}
于 2010-07-06T13:58:55.760 回答
1

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

{
  "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”等。

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

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

于 2010-07-06T14:05:28.633 回答
1

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

于 2010-07-06T14:06:24.250 回答
0

我认为您不能将其称为错误。就像您自己说的那样,没有关于对象属性如何排序的保证。

于 2010-07-06T13:59:53.063 回答
0

我发现使用 underscore.js 很容易解决

myArray = _.sortBy(myArray, function(num){ return Math.ceil(num); });

耶!myArray 在所有浏览器中都恢复了正确的顺序。

于 2013-05-07T22:58:33.767 回答
0

我的键对我来说太重要了,无法将它们转换为字符串。相反,我创建了另一个数组,它只维护了键的顺序。

<?php 
$origArray = valueReturnedFromFunction();
$preservedOrder = array_keys($origArray);
?>
<script>
var origArray = <?php echo json_encode($origArray)?>;
var preservedOrder = <?php echo json_encode($preservedOrder )?>;

for(i in preservedOrder){
    var item = origArray[i];
    ...
}
</script>
于 2018-12-11T17:29:21.127 回答