代码之家  ›  专栏  ›  技术社区  ›  Dimitar Christoff

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

  •  25
  • Dimitar Christoff  · 技术社区  · 14 年前

    {
      "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。。。循环中是:

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

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

    它只影响整数,似乎Webkit/Blink有一个优化 对象属性是数值的,可能与分支预测或其他有关。

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

    我想我记得我读过一篇文章,没有关于对象属性顺序的保证,但同时,这是非常烦人的,而且仅仅为chrome用户修复它会花费大量的精力。

    编辑 此外,我现在在v8 bug tracker上发现了一个问题:

    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 . 应用 _ 在键返回正确/预期顺序之前。

    人们仍在对此进行更新和编辑,因此-它似乎不会影响到 Map WeakMap , Set etc(如更新的主要示例所示)

    7 回复  |  直到 3 年前
        1
  •  24
  •   Michael Sparks    14 年前

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

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

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

        2
  •  1
  •   spender    14 年前

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

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

    {
        "7":{"sortOrder":1,"data":["9149","9139","10455","17208"]},
        "7.5":{"sortOrder":2,"data":["9140","9150","10456","17209"]}
        //etc
    }
    
        3
  •  1
  •   Tim Down    14 年前

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

        4
  •  1
  •   Mickael Lherminez hyankov    5 年前

    串。我最好的建议是在你所有的钥匙上使用相同的“精度”。

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

    即便如此,也没有任何保证,但更有可能的是,它们会以同样的顺序出现。

        5
  •  0
  •   Ridcully    14 年前

    我想你不能把这叫做虫子。就像你自己说的,对一个对象的属性如何排序没有保证。

        6
  •  0
  •   rink.attendant.6    9 年前

    我发现使用underline.js很容易

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

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

        7
  •  0
  •   Jeff Sturgis    6 年前

    我的钥匙对我来说太重要了,不能把它们转换成字符串。相反,我创建了另一个数组,它只是维持键的顺序。

    <?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>