json_encode не сохраняет порядок

У меня многомерный массив, в PHP:

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

Когда i json_encode этот массив в javascript через:

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

я получил:

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

Я хочу сохранить первый, а не второй идентификатор.

Возникает вопрос о том, что 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 

Этот подход также совместим с нецелыми ключами.

Вот код (предложенный pr1001 в аналогичном вопросе) для преобразования массива на стороне PHP. Он будет работать для одномерных массивов.

 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) ); } 

Проблема в том, что в JavaScript упорядочены только массивы, объекты – нет.

Если у вас есть что-то вроде:

 array( array( 'type' => 2 'id' => 6 ), array( 'type' => 4 'id' => 12 ), array( 'type' => 3 'id' => 19 ) ) 

Тогда в вашем JavaScript у вас будет массив объектов, и этот массив сохранит свой порядок.

Причина, по которой это не в порядке, состоит в том, что индекс вашего массива не начинался с 0, ключи были не в порядке, и в ключах были пробелы. Итак, при кодировании PHP превратил его в объект вместо массива.