sortir properti objek dan JSON.stringify


103

Aplikasi saya memiliki banyak sekali objek, yang saya rangkai dan simpan ke disk. Sayangnya, ketika objek dalam array dimanipulasi, dan terkadang diganti, properti pada objek terdaftar dalam urutan yang berbeda (urutan pembuatannya?). Ketika saya melakukan JSON.stringify () pada array dan menyimpannya, diff menunjukkan properti yang terdaftar dalam urutan yang berbeda, yang mengganggu ketika mencoba menggabungkan data lebih jauh dengan alat diff dan penggabungan.

Idealnya saya ingin mengurutkan properti objek dalam urutan abjad sebelum melakukan stringify, atau sebagai bagian dari operasi stringify. Ada kode untuk memanipulasi objek array di banyak tempat, dan mengubahnya untuk selalu membuat properti dalam urutan eksplisit akan sulit.

Saran akan sangat diterima!

Contoh kental:

obj = {}; obj.name="X"; obj.os="linux";
JSON.stringify(obj);
obj = {}; obj.os="linux"; obj.name="X";
JSON.stringify(obj);

Output dari dua panggilan stringify ini berbeda, dan muncul dalam perbedaan data saya, tetapi aplikasi saya tidak peduli tentang pengurutan properti. Benda-benda tersebut dibangun dengan berbagai cara dan tempat.


Berikan contoh objek yang Anda coba rangkai (baik keluaran JSON atau literal objek JS)
Bojangles

4
Kunci objek dalam objek tidak dijamin memiliki urutan tetap. Ini memang disengaja.
Pejalan kaki


1
@rab, darimana kamu menemukan itu? Catatan: Ini bisa berfungsi (dan mungkin sebagian besar waktu), tapi maksud saya itu tidak dijamin.
Dogbert

1
OP di sini. Tidak ada ketergantungan pada tatanan properti di sini, hanya pertanyaan tentang bagaimana menghindari perbedaan dalam data serial. Ini akhirnya diselesaikan dengan menyembunyikan properti dalam array dan mengurutkannya sebelum serialisasi, seperti dalam jawaban yang diterima di bawah ini.
Berinovasi

Jawaban:


80

Pendekatan yang lebih sederhana, modern, dan saat ini didukung browser hanyalah sebagai berikut:

JSON.stringify(sortMyObj, Object.keys(sortMyObj).sort());

Namun, metode ini menghapus objek bertingkat yang tidak direferensikan dan tidak berlaku untuk objek dalam array. Anda juga ingin meratakan objek penyortiran jika Anda menginginkan sesuatu seperti keluaran ini:

{"a":{"h":4,"z":3},"b":2,"c":1}

Anda dapat melakukannya dengan ini:

var flattenObject = function(ob) {
    var toReturn = {};

    for (var i in ob) {
        if (!ob.hasOwnProperty(i)) continue;

        if ((typeof ob[i]) == 'object') {
            var flatObject = flattenObject(ob[i]);
            for (var x in flatObject) {
                if (!flatObject.hasOwnProperty(x)) continue;

                toReturn[i + '.' + x] = flatObject[x];
            }
        } else {
            toReturn[i] = ob[i];
        }
    }
    return toReturn;
};

JSON.stringify(sortMyObj, Object.keys(flattenObject(sortMyObj)).sort());

Untuk melakukannya secara terprogram dengan sesuatu yang dapat Anda sesuaikan sendiri, Anda perlu memasukkan nama properti objek ke dalam larik, lalu mengurutkan larik secara alfabet dan mengulangi larik tersebut (yang akan berada dalam urutan yang benar) dan memilih setiap nilai dari objek di pesanan itu. "hasOwnProperty" juga dicentang jadi Anda pasti hanya memiliki properti objek itu sendiri. Berikut contohnya:

var obj = {"a":1,"b":2,"c":3};

function iterateObjectAlphabetically(obj, callback) {
    var arr = [],
        i;

    for (i in obj) {
        if (obj.hasOwnProperty(i)) {
            arr.push(i);
        }
    }

    arr.sort();

    for (i = 0; i < arr.length; i++) {
        var key = obj[arr[i]];
        //console.log( obj[arr[i]] ); //here is the sorted value
        //do what you want with the object property
        if (callback) {
            // callback returns arguments for value, key and original object
            callback(obj[arr[i]], arr[i], obj);
        }
    }
}

iterateObjectAlphabetically(obj, function(val, key, obj) {
    //do something here
});

Sekali lagi, ini akan menjamin bahwa Anda mengulang dalam urutan abjad.

Terakhir, melangkah lebih jauh untuk cara yang paling sederhana, pustaka ini secara rekursif akan memungkinkan Anda untuk mengurutkan JSON apa pun yang Anda berikan ke dalamnya: https://www.npmjs.com/package/json-stable-stringify

var stringify = require('json-stable-stringify');
var obj = { c: 8, b: [{z:6,y:5,x:4},7], a: 3 };
console.log(stringify(obj));

Keluaran

{"a":3,"b":[{"x":4,"y":5,"z":6},7],"c":8}

9
Ini sangat banyak yang saya coba hindari :) Tapi terima kasih, sepertinya solusi yang benar, jika berat,.
Berinovasi

1
Ada bug dalam kode ini. Anda tidak dapat mereferensikan obj[i]perulangan for karena imerupakan integer, dan nama propertinya belum tentu (oleh karena itu pertanyaan ini). Seharusnya begitu obj[arr[i]].
Andrew Ensley

1
Callback tidak eksklusif untuk perilaku asynchronous.
marksyzm

2
@Johann Dengan menggunakan panggilan balik di sini, dia berubah iterateObjectAlphabeticallymenjadi fungsi yang dapat digunakan kembali. Tanpa callback, 'kode payload' harus berada di dalam fungsi itu sendiri. Saya pikir ini adalah solusi yang sangat elegan dan yang digunakan di banyak perpustakaan dan inti JS itu sendiri. Misalnya Array.forEach .
Stijn de Witt

1
@marksyzm Tidak apa-apa, dalam kasus saya, saya harus merangkai hanya pilihan bidang. Jadi, jawaban Anda membuat saya di jalan. Terima kasih
Benj

39

Saya pikir jika Anda mengendalikan generasi JSON (dan kedengarannya seperti Anda), maka untuk tujuan Anda ini mungkin solusi yang baik: json-stable-stringify

Dari situs proyek:

deterministic JSON.stringify () dengan penyortiran kustom untuk mendapatkan hash deterministik dari hasil yang dirangkai

Jika JSON yang dihasilkan bersifat deterministik, Anda seharusnya dapat dengan mudah melakukan diff / menggabungkannya.


1
Perhatikan bahwa repo dalam kondisi buruk: belum diperbarui dalam 3 tahun dan memiliki masalah yang belum terselesaikan serta permintaan penarikan. Saya pikir lebih baik melihat beberapa jawaban yang lebih baru.
Tom

3
@Tom Juga perhatikan bahwa repo memiliki 5 juta unduhan mingguan (!). Dengan kata lain, ini digunakan secara aktif. Memiliki masalah terbuka yang 'belum terselesaikan' dan / atau permintaan tarik tidak berarti banyak. Hanya saja penulis tidak peduli dengan masalah tersebut atau tidak punya waktu dll. Tidak setiap lib perlu diperbarui setiap beberapa bulan. Nyatanya, imho, libs terbaik sangat jarang mendapatkan pembaruan. Ketika sesuatu selesai, itu selesai. Saya tidak mengatakan proyek ini tidak memiliki masalah nyata, tetapi jika demikian, tolong tunjukkan itu. Saya tidak terlibat dengan lib BTW ini.
Stijn de Witt

ES6 Saya rasa memecahkannya karena dapat mengurutkan objek (non-array), seperti yang ditentukan. Saya membutuhkan ini untuk mengedit pengguna. Sekalipun pesanan tidak masalah untuk komputer. Itu dilakukan untuk pengguna yang mengeditnya. Itu pantas untuk dicoba.
TamusJRoyce

1
Di atas apa yang dikatakan @Tom, saya juga akan menunjukkan bahwa proyek ini tidak memiliki dependensi waktu proses. Artinya jika tidak ada masalah keamanan / pemeliharaan di repo ini, maka mungkin cukup stabil dan aman untuk digunakan. Selain itu, saya baru saja mengujinya dengan ES6 dan tampaknya berfungsi dengan baik (setidaknya di Firefox).
Phil

28

Anda bisa meneruskan array yang diurutkan dari nama properti sebagai argumen kedua dari JSON.stringify():

JSON.stringify(obj, Object.keys(obj).sort())

1
Apakah ada jaminan yang terdokumentasi tentang perilaku ini?
rich remer

4
@richremer Ya, dalam standar ECMAScript , parameter kedua JSON.stringify()dipanggil replacerdan dapat berupa array. Ini digunakan untuk membangun PropertyListyang kemudian digunakan SerializeJSONObject()untuk menambahkan properti dalam urutan itu. Ini didokumentasikan sejak ECMAScript 5.
Christian d'Heureuse

15
Perhatikan bahwa jika obj memiliki objek bersarang di dalamnya, kunci bersarang harus ada di argumen kedua juga; jika tidak, mereka akan dijatuhkan! Kontra-contoh: > JSON.stringify({a: {c: 1, b: 2}}, ['a']) '{"a":{}}' Satu cara (hacky) untuk membangun daftar semua kunci yang relevan adalah dengan menggunakan JSON.stringify untuk melintasi objek: function orderedStringify(obj) { const allKeys = []; JSON.stringify(obj, (k, v) => { allKeys.push(k); return v; }); return JSON.stringify(obj, allKeys.sort()); } Contoh:> orderedStringify({a: {c: 1, b: 2}}) '{"a":{"b":2,"c":1}}'
Saif Hakim

1
Object.keys () tidak rekursif. Ini tidak akan berfungsi untuk objek apa pun yang berisi larik atau objek bertingkat.
Jor

28

Saya tidak mengerti mengapa kompleksitas jawaban terbaik saat ini diperlukan, untuk mendapatkan semua kunci secara rekursif. Kecuali jika kinerja yang sempurna diperlukan, bagi saya tampaknya kita hanya dapat menelepon JSON.stringify()dua kali, pertama kali untuk mendapatkan semua kunci, dan kedua, untuk benar-benar melakukan pekerjaan itu. Dengan cara itu, semua kompleksitas rekursi ditangani oleh stringify, dan kita tahu bahwa rekursi mengetahui barangnya, dan cara menangani setiap jenis objek:

function JSONstringifyOrder( obj, space )
{
    var allKeys = [];
    JSON.stringify( obj, function( key, value ){ allKeys.push( key ); return value; } )
    allKeys.sort();
    return JSON.stringify( obj, allKeys, space );
}

itu menarik, tapi Anda sebenarnya "curang" menggunakan stringify untuk memetakan semua kunci ke sebuah array. Array itu bisa lebih mudah, lebih baik dan lebih aman diperoleh melalui Object.keys
Bernardo Dal Corno

6
Tidak, intinya adalah itu Object.keys()tidak rekursif, jadi jika Anda memiliki objek seperti {a: "A", b: {c: "C"} }dan Anda memanggil Object.keys di atasnya, Anda hanya akan mendapatkan kunci adan b, tetapi tidak c. JSON.stringifymengetahui segala sesuatu tentang rekursi pada setiap jenis objek yang ditangani oleh proses serialisasi JSON, baik itu seperti objek atau array (dan itu sudah mengimplementasikan logika untuk mengenali keduanya), jadi itu harus menangani semuanya dengan benar untuk kita.
Jor

1
Suka solusi ini, tampaknya sangat elegan dan gagal aman.
Markus

@Jor terima kasih, itu berhasil untuk saya. Potongan lain yang saya coba gagal dengan satu atau lain cara.
nevf

14

Perbarui 2018-7-24:

Versi ini mengurutkan objek bersarang dan mendukung larik juga:

function sortObjByKey(value) {
  return (typeof value === 'object') ?
    (Array.isArray(value) ?
      value.map(sortObjByKey) :
      Object.keys(value).sort().reduce(
        (o, key) => {
          const v = value[key];
          o[key] = sortObjByKey(v);
          return o;
        }, {})
    ) :
    value;
}


function orderedJsonStringify(obj) {
  return JSON.stringify(sortObjByKey(obj));
}

Kasus cobaan:

  describe('orderedJsonStringify', () => {
    it('make properties in order', () => {
      const obj = {
        name: 'foo',
        arr: [
          { x: 1, y: 2 },
          { y: 4, x: 3 },
        ],
        value: { y: 2, x: 1, },
      };
      expect(orderedJsonStringify(obj))
        .to.equal('{"arr":[{"x":1,"y":2},{"x":3,"y":4}],"name":"foo","value":{"x":1,"y":2}}');
    });

    it('support array', () => {
      const obj = [
        { x: 1, y: 2 },
        { y: 4, x: 3 },
      ];
      expect(orderedJsonStringify(obj))
        .to.equal('[{"x":1,"y":2},{"x":3,"y":4}]');
    });

  });

Jawaban yang tidak berlaku lagi:

Versi ringkas di ES2016. Penghargaan untuk @codename, dari https://stackoverflow.com/a/29622653/94148

function orderedJsonStringify(o) {
  return JSON.stringify(Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {}));
}

Sintaksnya kurang tepat. Seharusnya -function orderedJsonStringify(o) { return JSON.stringify(Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {})); }
Ben

Ini, untuk saat ini, telah memperbaiki masalah saya dengan C # DataContractJsonSerializer dan "__type" yang tidak terdaftar pertama kali dalam string json. Terima kasih.
Yogurt The Wise

2
Perhatikan bahwa ini, seperti jawaban Christian, berperilaku tidak tepat dengan objek bersarang.
Daniel Griscom

sortObjPropertiesByKey tidak ditentukan. Apakah Anda bermaksud menggunakan sortObjByKey?
Paul Lynch

Tampaknya ini tidak sortObjByKey()memeriksa referensi melingkar, jadi berhati-hatilah, ini mungkin menggantung dalam loop tak terbatas tergantung pada data masukan. Contoh: var objA = {}; var objB = {objA: objA}; objA.objB = objB;-> sortObjByKey(objA);->VM59:6 Uncaught RangeError: Maximum call stack size exceeded
Klesun


4

Ini sama dengan jawaban Satpal Singh

function stringifyJSON(obj){
    keys = [];
    if(obj){
        for(var key in obj){
            keys.push(key);
        }
    }
    keys.sort();
    var tObj = {};
    var key;
    for(var index in keys){
        key = keys[index];
        tObj[ key ] = obj[ key ];
    }
    return JSON.stringify(tObj);
}

obj1 = {}; obj1.os="linux"; obj1.name="X";
stringifyJSON(obj1); //returns "{"name":"X","os":"linux"}"

obj2 = {}; obj2.name="X"; obj2.os="linux";
stringifyJSON(obj2); //returns "{"name":"X","os":"linux"}"

3

Anda dapat menambahkan toJSONfungsi khusus ke objek Anda yang dapat Anda gunakan untuk menyesuaikan keluaran. Di dalam fungsi, menambahkan properti saat ini ke objek baru dalam urutan tertentu harus mempertahankan urutan itu saat dirangkai.

Lihat disini:

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON/stringify

Tidak ada metode bawaan untuk mengontrol pengurutan karena data JSON dimaksudkan untuk diakses oleh kunci.

Berikut adalah jsfiddle dengan contoh kecil:

http://jsfiddle.net/Eq2Yw/

Cobalah mengomentari toJSONfungsinya - urutan propertinya dibalik. Perlu diketahui bahwa ini mungkin khusus browser, yaitu pemesanan tidak didukung secara resmi dalam spesifikasi. Ini berfungsi di versi Firefox saat ini, tetapi jika Anda menginginkan solusi yang 100% kuat, Anda mungkin harus menulis fungsi stringifier Anda sendiri.

Edit:

Lihat juga pertanyaan SO ini tentang keluaran non-deterministik stringify, terutama detail Daff tentang perbedaan browser:

Bagaimana cara memverifikasi secara deterministik bahwa objek JSON belum dimodifikasi?


Properti dari setiap objek dikenal (dan sebagian besar berupa string) jadi hardcode properti di stringifier toJSON saya sendiri mungkin jauh lebih cepat daripada menyortir ...!
Berinovasi

'OrderJsonStringify 'di bawah hampir berfungsi. Tapi ini tampaknya menjadi solusi yang lebih baik bagi saya. Ketika saya perlu mendapatkan '__type' dari C # DataContractJsonSerializer untuk menjadi item pertama dalam string json. var json = JSON.stringify (myjsonobj, ['__type', 'id', 'text', 'somesubobj' dll .....]); sedikit sakit untuk memiliki daftar semua kunci.
Yogurt The Wise

3

Jawaban rekursif dan sederhana:

function sortObject(obj) {
    if(typeof obj !== 'object')
        return obj
    var temp = {};
    var keys = [];
    for(var key in obj)
        keys.push(key);
    keys.sort();
    for(var index in keys)
        temp[keys[index]] = sortObject(obj[keys[index]]);       
    return temp;
}

var str = JSON.stringify(sortObject(obj), undefined, 4);

reorderharus diganti namanya menjadi sortObjectdan ini tidak menangani larik
Jonathan Gawrych

Terima kasih telah memperhatikan itu, dan masalah OP adalah menggunakan objek, bukan array.
Jason Parham

@JonathanGawrych Mengapa Anda tetap mengurutkan array, mereka seharusnya memiliki pesanan. Larik [1,2,3] tidak sama dengan larik [2,3,1], tetapi objek tidak memiliki urutan properti. Masalahnya adalah bahwa urutan tiba-tiba menjadi penting setelah stringifikasi - string untuk 100% objek yang setara bisa berbeda. Sayangnya upaya untuk mendapatkan stringify deterministik tampaknya cukup besar, contoh paket: github.com/substack/json-stable-stringify/blob/master/index.js
Mörre

1
@ Mörre - Saya rasa saya tidak cukup spesifik. Dengan "tidak menangani array," maksud saya array rusak, tidak dibiarkan tanpa urutan. Masalahnya adalah karena typeof arr === "object"itu akan mengubah array menjadi objek. Misalnya var obj = {foo: ["bar", "baz"]}akan { "foo": { "0": "bar", "1": "baz"} }
dirangkai

untuk memperbaiki masalah yang ditemukan oleh @JonathanGawrych:if(obj.constructor.prototype !== Object.prototype)
ricka

3

Anda dapat mengurutkan objek berdasarkan nama properti di EcmaScript 2015

function sortObjectByPropertyName(obj) {
    return Object.keys(obj).sort().reduce((c, d) => (c[d] = obj[d], c), {});
}

Mungkin nama yang lebih baik sortObjectPropertiesByName()atau lebih sederhana sortPropertiesByName().
Jan

3

Saya mengambil jawaban dari @Jason Parham dan membuat beberapa perbaikan

function sortObject(obj, arraySorter) {
    if(typeof obj !== 'object')
        return obj
    if (Array.isArray(obj)) {
        if (arraySorter) {
            obj.sort(arraySorter);
        }
        for (var i = 0; i < obj.length; i++) {
            obj[i] = sortObject(obj[i], arraySorter);
        }
        return obj;
    }
    var temp = {};
    var keys = [];
    for(var key in obj)
        keys.push(key);
    keys.sort();
    for(var index in keys)
        temp[keys[index]] = sortObject(obj[keys[index]], arraySorter);       
    return temp;
}

Ini memperbaiki masalah larik yang diubah menjadi objek, dan ini juga memungkinkan Anda untuk menentukan cara mengurutkan larik.

Contoh:

var data = { content: [{id: 3}, {id: 1}, {id: 2}] };
sortObject(data, (i1, i2) => i1.id - i2.id)

keluaran:

{content:[{id:1},{id:2},{id:3}]}

2

Jawaban yang diterima tidak berfungsi untuk saya untuk objek bersarang karena beberapa alasan. Ini membuat saya membuat kode saya sendiri. Karena akhir 2019 ketika saya menulis ini, ada beberapa opsi lagi yang tersedia dalam bahasa ini.

Pembaruan: Saya percaya jawaban David Furlong adalah pendekatan yang lebih disukai untuk upaya saya sebelumnya, dan saya telah mengesampingkannya. Milik saya mengandalkan dukungan untuk Object.entries (...), jadi tidak ada dukungan Internet Explorer.

function normalize(sortingFunction) {
  return function(key, value) {
    if (typeof value === 'object' && !Array.isArray(value)) {
      return Object
        .entries(value)
        .sort(sortingFunction || undefined)
        .reduce((acc, entry) => {
          acc[entry[0]] = entry[1];
          return acc;
        }, {});
    }
    return value;
  }
}

JSON.stringify(obj, normalize(), 2);

-

MEMPERTAHANKAN VERSI LAMA INI UNTUK REFERENSI SEJARAH

Saya menemukan bahwa array datar sederhana dari semua kunci di objek akan berfungsi. Di hampir semua browser (bukan Edge atau Internet explorer, dapat diprediksi) dan Node 12+ ada solusi yang cukup singkat sekarang karena Array.prototype.flatMap (...) tersedia. (Setara lodash akan berfungsi juga.) Saya hanya menguji di Safari, Chrome, dan Firefox, tetapi saya tidak melihat alasan mengapa itu tidak akan berfungsi di tempat lain yang mendukung flatMap dan standar JSON.stringify (...) .

function flattenEntries([key, value]) {
  return (typeof value !== 'object')
    ? [ [ key, value ] ]
    : [ [ key, value ], ...Object.entries(value).flatMap(flattenEntries) ];
}

function sortedStringify(obj, sorter, indent = 2) {
  const allEntries = Object.entries(obj).flatMap(flattenEntries);
  const sorted = allEntries.sort(sorter || undefined).map(entry => entry[0]);
  return JSON.stringify(obj, sorted, indent);
}

Dengan ini, Anda dapat merangkai tanpa dependensi pihak ketiga dan bahkan meneruskan algoritme pengurutan Anda sendiri yang mengurutkan pasangan entri nilai kunci, sehingga Anda dapat mengurutkan berdasarkan kunci, payload, atau kombinasi keduanya. Berfungsi untuk objek bersarang, larik, dan campuran apa pun dari tipe data lama biasa.

const obj = {
  "c": {
    "z": 4,
    "x": 3,
    "y": [
      2048,
      1999,
      {
        "x": false,
        "g": "help",
        "f": 5
      }
    ]
  },
  "a": 2,
  "b": 1
};

console.log(sortedStringify(obj, null, 2));

Cetakan:

{
  "a": 2,
  "b": 1,
  "c": {
    "x": 3,
    "y": [
      2048,
      1999,
      {
        "f": 5,
        "g": "help",
        "x": false
      }
    ],
    "z": 4
  }
}

Jika Anda harus memiliki kompatibilitas dengan mesin JavaScript yang lebih lama , Anda dapat menggunakan versi yang sedikit lebih panjang ini yang meniru perilaku flatMap. Klien harus mendukung setidaknya ES5, jadi tidak ada Internet Explorer 8 atau yang lebih rendah.

Ini akan mengembalikan hasil yang sama seperti di atas.

function flattenEntries([key, value]) {
  if (typeof value !== 'object') {
    return [ [ key, value ] ];
  }
  const nestedEntries = Object
    .entries(value)
    .map(flattenEntries)
    .reduce((acc, arr) => acc.concat(arr), []);
  nestedEntries.unshift([ key, value ]);
  return nestedEntries;
}

function sortedStringify(obj, sorter, indent = 2) {
  const sortedKeys = Object
    .entries(obj)
    .map(flattenEntries)
    .reduce((acc, arr) => acc.concat(arr), [])
    .sort(sorter || undefined)
    .map(entry => entry[0]);
  return JSON.stringify(obj, sortedKeys, indent);
}

1

Bekerja dengan lodash, objek bersarang, nilai apa pun dari atribut objek:

function sort(myObj) {
  var sortedObj = {};
  Object.keys(myObj).sort().forEach(key => {
    sortedObj[key] = _.isPlainObject(myObj[key]) ? sort(myObj[key]) : myObj[key]
  })
  return sortedObj;
}
JSON.stringify(sort(yourObj), null, 2)

Ini bergantung pada perilaku Chrome dan Node di mana kunci pertama yang ditetapkan ke suatu objek dikeluarkan pertama oleh JSON.stringify.


2
Terima kasih, tetapi saya mengalami masalah ini 4 tahun yang lalu, dengan senang hati saya katakan bahwa saya telah pindah sedikit sejak saat itu :)
Inovasi

1
:) Senang mendengarnya. Meskipun saya mengalami masalah ini kemarin dan tidak menemukan jawaban yang saya cari di bawah pertanyaan Anda (lama tapi masih relevan) :)
AJP

0

Mencoba:

function obj(){
  this.name = '';
  this.os = '';
}

a = new obj();
a.name = 'X',
a.os = 'linux';
JSON.stringify(a);
b = new obj();
b.os = 'linux';
b.name = 'X',
JSON.stringify(b);

Terima kasih, tetapi tampaknya pemesanannya tidak ditentukan dan hanya berhasil. Pendekatan yang menarik sekalipun!
Berinovasi

0

Saya membuat fungsi untuk mengurutkan objek, dan dengan callback .. yang sebenarnya membuat objek baru

function sortObj( obj , callback ) {

    var r = [] ;

    for ( var i in obj ){
        if ( obj.hasOwnProperty( i ) ) {
             r.push( { key: i , value : obj[i] } );
        }
    }

    return r.sort( callback ).reduce( function( obj , n ){
        obj[ n.key ] = n.value ;
        return obj;
    },{});
}

dan menyebutnya dengan objek.

var obj = {
    name : "anu",
    os : "windows",
    value : 'msio',
};

var result = sortObj( obj , function( a, b ){
    return a.key < b.key  ;    
});

JSON.stringify( result )

yang mencetak {"value":"msio","os":"windows","name":"anu"}, dan untuk menyortir dengan nilai.

var result = sortObj( obj , function( a, b ){
    return a.value < b.value  ;    
});

JSON.stringify( result )

yang mencetak {"os":"windows","value":"msio","name":"anu"}


1
Bekerja dengan baik, tapi sayangnya ini tidak rekursif.
Jonathan Gawrych

0

Jika objek dalam daftar tidak memiliki properti yang sama, buat objek master gabungan sebelum stringify:

let arr=[ <object1>, <object2>, ... ]
let o = {}
for ( let i = 0; i < arr.length; i++ ) {
  Object.assign( o, arr[i] );
}
JSON.stringify( arr, Object.keys( o ).sort() );


0
function FlatternInSort( obj ) {
    if( typeof obj === 'object' )
    {
        if( obj.constructor === Object )
        {       //here use underscore.js
            let PaireStr = _( obj ).chain().pairs().sortBy( p => p[0] ).map( p => p.map( FlatternInSort ).join( ':' )).value().join( ',' );
            return '{' + PaireStr + '}';
        }
        return '[' + obj.map( FlatternInSort ).join( ',' ) + ']';
    }
    return JSON.stringify( obj );
}

// contoh seperti di bawah ini. dalam setiap lapisan, untuk objek seperti {}, diratakan dalam urutan kunci. untuk array, angka atau string, diratakan seperti / dengan JSON.stringify.

FlatternInSort ({c: 9, b: {y: 4, z: 2, e: 9}, F: 4, a: [{j: 8, h: 3}, {a: 3, b: 7}] })

"{" F ": 4," a ": [{" h ": 3," j ": 8}, {" a ": 3," b ": 7}]," b ": {" e " : 9, "y": 4, "z": 2}, "c": 9} "


Harap jelaskan mengapa menggunakan lib eksternal, dan seperti yang dikatakan @DeKaNszn, tambahkan beberapa penjelasan dan pengantar. Itu akan sangat dihargai.
Benj

fungsi ini disalin dari proyek saya. di mana saya menggunakan underscore.js.
saintthor

0

Memperluas jawaban AJP, untuk menangani array:

function sort(myObj) {
    var sortedObj = {};
    Object.keys(myObj).sort().forEach(key => {
        sortedObj[key] = _.isPlainObject(myObj[key]) ? sort(myObj[key]) : _.isArray(myObj[key])? myObj[key].map(sort) : myObj[key]
    })
    return sortedObj;
}

0

Terkejut tidak ada yang menyebutkan isEqualfungsi lodash .

Melakukan perbandingan mendalam antara dua nilai untuk menentukan apakah keduanya setara.

Catatan: Metode ini mendukung perbandingan array, buffer array, boolean, objek tanggal, objek kesalahan, peta, angka, objek objek, ekspresi reguler, set, string, simbol, dan array yang diketik. Objek objek dibandingkan dengan properti mereka sendiri, bukan diwarisi, dan dapat dihitung. Fungsi dan simpul DOM dibandingkan dengan persamaan yang ketat, yaitu ===.

https://lodash.com/docs/4.17.11#isEqual

Dengan masalah awal - kunci yang diurutkan secara tidak konsisten - ini adalah solusi yang bagus - dan tentu saja ini hanya akan berhenti jika menemukan konflik alih-alih menyusun seluruh objek secara membabi buta.

Untuk menghindari mengimpor seluruh pustaka Anda melakukan ini:

import { isEqual } from "lodash-es";

Contoh bonus: Anda juga dapat menggunakan ini dengan RxJS dengan operator kustom ini

export const distinctUntilEqualChanged = <T>(): MonoTypeOperatorFunction<T> => 
                                                pipe(distinctUntilChanged(isEqual));

0

Bagaimanapun, ini membutuhkan Array yang menyimpan semua kunci dalam objek bersarang (jika tidak maka akan menghilangkan kunci yang tidak di-cache.) Jawaban terlama salah, karena argumen kedua tidak peduli dengan notasi titik. Jadi, jawabannya (menggunakan Set) menjadi.

function stableStringify (obj) {
  const keys = new Set()
  const getAndSortKeys = (a) => {
    if (a) {
      if (typeof a === 'object' && a.toString() === '[object Object]') {
        Object.keys(a).map((k) => {
          keys.add(k)
          getAndSortKeys(a[k])
        })
      } else if (Array.isArray(a)) {
        a.map((el) => getAndSortKeys(el))
      }
    }
  }
  getAndSortKeys(obj)
  return JSON.stringify(obj, Array.from(keys).sort())
}

0

Berikut adalah pendekatan klon ... kloning objek sebelum mengonversi ke json:

function sort(o: any): any {
    if (null === o) return o;
    if (undefined === o) return o;
    if (typeof o !== "object") return o;
    if (Array.isArray(o)) {
        return o.map((item) => sort(item));
    }
    const keys = Object.keys(o).sort();
    const result = <any>{};
    keys.forEach((k) => (result[k] = sort(o[k])));
    return result;
}

Jika sangat baru tetapi tampaknya berfungsi pada file package.json baik-baik saja.


-3

Ada Array.sortmetode yang bisa membantu Anda. Sebagai contoh:

yourBigArray.sort(function(a,b){
    //custom sorting mechanism
});

1
Saya tidak ingin mengurutkan array. Sebenarnya bagian array tidak penting .. Saya ingin mengurutkan properti dari suatu objek .. dari beberapa percobaan cepat sepertinya properti terdaftar dalam urutan pembuatannya. Salah satu caranya mungkin dengan membuat objek baru dan menyalin properti dalam urutan abjad tetapi saya berharap ada sesuatu yang lebih mudah / lebih cepat ..
Innovine

1
@Innovine, meskipun itu tidak akan berfungsi karena kunci tidak dijamin akan diurutkan berdasarkan waktu pembuatan oleh spesifikasi.
Dogbert

Kemudian pertanyaannya menjadi, bagaimana cara merangkai objek saya sedemikian rupa sehingga kunci berada dalam urutan tetap .. bukan tidak mungkin bagi saya untuk melakukan (key in obj) dan menyimpannya dalam array temp dan mengurutkannya dan secara manual membangun sebuah string .. tapi saya sangat berharap ada cara yang lebih mudah
Innovine

Tidak, begitulah cara melakukannya. Selamat datang di JavaScript.
marksyzm
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.