json_encode不能保持顺序

28

我有一个 PHP 中的多维数组:

Array
(
[1] => Array
    (
        [19] => Array
            (                    
                [type] => 2
            )            
        [6] => Array
            (                    
                [type] => 4
            )
        [12] => Array
            (                    
                [type] => 3
            )
    )

)

当我在JavaScript中使用以下代码对此数组进行json编码:

 var jsonArray = <?php echo json_encode($above_array); ?>;

我理解为:

 Object
 (
 [1] => Object
 (
    [6] => Object
        (                    
            [type] => 2
        )
    [12] => Object
        (                    
            [type] => 4
        )
    [19] => Object
        (                    
            [type] => 3
        )
)

)

我希望保留第一排序而不是按id保留第二排序。


我该如何保留第一顺序? - croppio.com
使用其他键作为关键字(例如key_1、key_2、key3),这样在解码JSON后可以进行排序。 - Lorenzo Aiello
1
http://php.net/manual/en/function.json-encode.php#107616 - Amal Murali
1
JSON对象是无序的键值映射。数组是有序列表。选择吧,Javascript/JSON没有有序映射。 - deceze
如果您想保留顺序,您需要一个数组而不是一个对象。您需要生成一个类似于这样的结构:[[19, {type: 2}], [9, { type: 2}], [6, {type: 4}], [12, {type: 3}]],也就是一个包含两个元素的嵌套数组,其中每个嵌套数组都包含“索引”和type对象。 - user229044
可能是重复的问题:如何阻止Chrome和Opera按索引升序排序JSON对象? - Organic Advocate
4个回答

23

在StackOverflow上有一个问题:JavaScript是否保证对象属性顺序? 简而言之,答案是否定的。所以,当将PHP数组转换为Javascript对象时,键的顺序将不会被保留。

PHP和Javascript数组之间的主要区别在于后者只能持有从零开始的连续整数键。因此,并不总是可能将PHP数组转换为Javascript数组。 让我们来看几个例子:

// example 1
echo json_encode(array(0 => 'a', 1 => 'b')) // outputs ["a","b"]

// example 2
echo json_encode(array(0 => 'a', 3 => 'b')) // outputs {"0":"a","3":"b"}

// example 3
echo json_encode(array(3 => 'b', 0 => 'a')) // outputs {"3":"b","0":"a"}, but in Javascript the key order will be the same as in example 2
  1. 在第一个示例中,json_encode 将 PHP 数组转换为相同的 JavaScript 数组。
  2. 在第二个示例中,它转换为对象,因为键的顺序不是连续的。
  3. 在第三个示例中,它也转换为对象。但在 JavaScript 中,对象 2 和 3 将是相同的,具有相同的键顺序,即使键按不同顺序列出。因此,不是 json_encode 函数没有保留键顺序,而是 JavaScript 本身。

回到我们的问题:如何传递 PHP 数组以保留键顺序到 JavaScript? 一种方法是将 PHP 键值对包装到数组中:

// original array:
array(
    3 => 'b', 
    0 => 'a'
)

// must be converted to:
array(
    array(3, 'b'),
    array(0, 'a')
)

然后json_encode将产生以下Javascript数组:

[
  [3,"b"],
  [0,"a"]
]

最后一部分是在JavaScript中遍历这样的数组:

var php_encoded_array = [
  [3,"b"],
  [0,"a"]
];

for (var i=0; i < php_encoded_array.length; i++) {
  var rec = php_encoded_array[i],
      key = rec[0],
      value = rec[1];

  console.log(key + ': ' + value);
}
// It will output:
// 3: b
// 0: a
// Which is the exact same order as in the PHP array

这种方法也适用于非整数键。

以下是在PHP端将数组转换的代码(由类似问题中的pr1001建议)。 它适用于一维数组。

array_map(
    function($key, $value) { return array($key, $value); },
    array_keys($data),
    array_values($data)
)

下面是一个递归函数实现多维数组的示例:

function array_preserve_js_order(array $data) {
    return array_map(
        function($key, $value) {
            if (is_array($value)) {
                $value = array_preserve_js_order($value);
            }
            return array($key, $value);
        },
        array_keys($data),
        array_values($data)
    );
}

6
问题在于JavaScript中只有数组是有序的,对象不是有序的。
如果你有这样一个东西:
array(
    array(
        'type' => 2
        'id' => 6
    ),
    array(
        'type' => 4
        'id' => 12
    ),
    array(
        'type' => 3
        'id' => 19
    )
)

在JavaScript中,您将拥有一个对象数组,并且该数组将保留其顺序。

如果您的数组索引没有从0开始,键不按顺序排列并且键之间存在间隙,则它的顺序就会错乱。因此,在编码时,PHP将其转换为对象而不是数组。


6
为了保持PHP数组的顺序,请使用array_values()函数。
<?php $php_array = array_values($php_array); ?>
var jsonArray = JSON.parse('<?php echo json_encode($php_array); ?>');

我喜欢当人们发布简单的解决方案。谢谢! - Adrian P.

0

由于这是一个古老的问题,我想把我的情况放进来。首先注意在(Chrome)控制台 > 网络 > 响应中,数组可能会作为您的 php JSON 的一部分以正确的顺序返回。然后将其与控制台 > 网络 > 预览进行比较,顺序会丢失。

我想要的输出结果是下拉框,我希望下拉选项按字母顺序排序。使用 Jquery,我实际上能够在这里实现这一点: 使用 jQuery 按字母顺序对选项元素进行排序

我使用了 Gerbus 的答案,我非常怀疑它可以移植到除下拉框之外的大多数其他基于 Jquery 的情况中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接