nesne özelliklerini ve JSON.stringify'ı sıralayın


106

Uygulamamın geniş bir nesne dizisi var, bunları dizgiye ekleyip diske kaydediyorum. Ne yazık ki, dizideki nesneler işlendiğinde ve bazen değiştirildiğinde, nesneler üzerindeki özellikler farklı sıralarda listelenir (yaratma sıraları?). Dizi üzerinde JSON.stringify () yaptığımda ve kaydettiğimde, bir fark, farklı sıralarda listelenen özellikleri gösteriyor, bu da verileri diff ve birleştirme araçlarıyla daha fazla birleştirmeye çalışırken can sıkıcı oluyor.

İdeal olarak, stringify işlemini gerçekleştirmeden önce veya stringify işleminin bir parçası olarak nesnelerin özelliklerini alfabetik sırada sıralamak istiyorum. Pek çok yerde dizi nesnelerini işlemek için bir kod vardır ve bunları her zaman açık bir sırayla özellikler oluşturmak için değiştirmek zor olacaktır.

Öneriler memnuniyetle karşılanacaktır!

Kısaltılmış bir örnek:

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

Bu iki stringify çağrısının çıktısı farklı ve verilerimin bir farkında görünüyor, ancak uygulamam özelliklerin sıralamasıyla ilgilenmiyor. Nesneler birçok şekilde ve yerde inşa edilmiştir.


Lütfen dizgeleştirmeye çalıştığınız nesnenin bir örneğini verin (JSON çıkışı veya JS nesnesi değişmez)
Bojangles

4
Nesnelerdeki nesne anahtarlarının sabit bir sıraya sahip olması garanti edilmez. Bu tasarım gereğidir.
Yoldan geçen


1
@rab, bunu nereden buldun? Not: Çalışabilir (ve muhtemelen çoğu zaman işe yarar), ancak bunun garanti edilmediğini kastettim.
Dogbert

1
Burada OP. Burada mülkiyet düzenine bağımlılık yoktu, sadece serileştirilmiş verilerde farklardan nasıl kaçınılacağına dair bir soru. Bu sonuçta, aşağıdaki kabul edilen cevapta olduğu gibi, özelliklerin dizilerde saklanması ve serileştirmeden önce sıralanmasıyla çözüldü.
Innovine

Yanıtlar:


85

Daha basit, modern ve şu anda tarayıcı destekli yaklaşım basitçe şudur:

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

Ancak bu yöntem, başvurulmayan ve dizilerdeki nesnelere uygulanmayan iç içe geçmiş nesneleri kaldırır. Şu çıktı gibi bir şey istiyorsanız, sıralama nesnesini de düzleştirmek isteyeceksiniz:

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

Bunu bununla yapabilirsiniz:

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

Kendiniz ayarlayabileceğiniz bir şeyle programlı olarak yapmak için, nesne özellik adlarını bir diziye itmeniz, ardından diziyi alfabetik olarak sıralamanız ve bu dizi boyunca yinelemeniz (doğru sırada olacaktır) ve nesneden her bir değeri seçmeniz gerekir. bu sipariş. "hasOwnProperty" de işaretlenir, böylece kesinlikle yalnızca nesnenin kendi özelliklerine sahip olursunuz. İşte bir örnek:

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

Yine, bu, alfabetik sıraya göre yinelemenizi garanti etmelidir.

Son olarak, en basit şekilde daha da ileri götürürsek, bu kitaplık, içine aktardığınız herhangi bir JSON'u yinelemeli olarak sıralamanıza izin verecektir: 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));

Çıktı

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

9
Kaçınmaya çalıştığım şey bu :) Ama teşekkürler, ağırsa doğru çözüm gibi görünüyor.
Innovine

1
Bu kodda bir hata var. obj[i]For döngüsünde referans olamaz çünkü ibir tamsayıdır ve özellik adları zorunlu değildir (dolayısıyla bu soru). Olmalı obj[arr[i]].
Andrew Ensley

1
Geri aramalar, zaman uyumsuz davranışa özel değildir.
marksyzm

2
@Johann Burada bir geri arama kullanarak, iterateObjectAlphabeticallytekrar kullanılabilir bir işleve dönüşür . Geri çağırma olmadan, 'yük kodu' işlevin kendisinin içinde olmalıdır. Bence bu çok zarif bir çözüm ve birçok kitaplıkta ve JS çekirdeğinde kullanılan bir çözüm. Örneğin Array.forEach .
Stijn de Witt

1
@marksyzm Sorun değil, benim durumumda yalnızca bazı alanları sıkıştırmak zorunda kaldım. Böylece cevabınız beni yola koydu. Teşekkürler
Benj

39

JSON neslinin kontrolündeyseniz (ve kulağa öyle geliyorsa), o zaman amaçlarınız için bu iyi bir çözüm olabilir: json-stabil-stringify

Proje web sitesinden:

Diziselleştirilmiş sonuçlardan deterministik karmalar almak için özel sıralama ile deterministik JSON.stringify ()

Üretilen JSON deterministik ise, onu kolayca ayırt edebilmeli / birleştirebilmelisin.


1
Deponun kötü durumda olduğuna dikkat edin: 3 yıldır güncellenmedi ve çözülmemiş sorunlar ve çekme talepleri var. Yeni cevaplardan bazılarına bakmanın daha iyi olacağını düşünüyorum.
Tom

3
@Tom Ayrıca bu deponun haftalık 5 milyon (!) İndirilmesi olduğunu unutmayın. Başka bir deyişle, aktif olarak kullanılıyor. 'Çözülmemiş' açık sorunlar ve / veya çekme talepleri olması pek bir şey ifade etmiyor. Sadece yazar (lar) bu konuları umursamıyor veya zamanları yok vs. Her kitaplığın birkaç ayda bir güncellenmesi gerekmiyor. Aslında, imho, en iyi kütüphaneler güncellemeleri çok seyrek alırlar. Bir şey yapıldığında biter. Bu projenin gerçek sorunları olmadığını söylemiyorum ama eğer öyleyse lütfen bunları belirtin. Bu lib BTW ile hiçbir ilgim yok.
Stijn de Witt

ES6 Sanırım nesneleri (dizi olmayanları) belirtildiği gibi sıralayabilmek için kırdı. Kullanıcı düzenleme için buna ihtiyacım var. Bilgisayar için sipariş önemli olmasa bile. Düzenleyen kullanıcılara yapar. Denemeye değerdi.
TamusJRoyce

1
@ Tom'un söylediklerinin yanı sıra, bu projenin çalışma zamanı bağımlılıkları olmadığını da belirteceğim. Yani bu depoda herhangi bir güvenlik / bakım sorunu yoksa, muhtemelen oldukça kararlı ve kullanımı güvenlidir. Ayrıca, ES6 ile test ettim ve iyi çalışıyor gibi görünüyor (en azından Firefox'ta).
Phil

29

Tüm anahtarları yinelemeli olarak almak için mevcut en iyi yanıtların karmaşıklığının neden gerekli olduğunu anlamıyorum. Mükemmel performans gerekmediği sürece, bana öyle geliyor ki JSON.stringify(), ilk kez tüm anahtarları almak için ve ikinci kez işi gerçekten yapmak için iki kez arayabiliriz . Bu şekilde, tüm özyineleme karmaşıklığı ele alınır stringifyve onun işlerini ve her nesne türünün nasıl ele alınacağını bildiğini biliyoruz:

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

bu ilginç, ancak aslında stringify kullanarak tüm anahtarları bir diziye eşlemek için "aldattınız". Bu dizi Object.keys aracılığıyla daha kolay, daha iyi ve daha güvenli elde edilebilir
Bernardo Dal Corno

6
Hayır, asıl mesele yani Object.keys()sizin gibi bir nesne var eğer öyleyse, değil özyinelemeli edilir {a: "A", b: {c: "C"} }ve bunun üzerine Object.keys diyoruz, sadece anahtarlarını alacak ave bancak c. JSON.stringifyJSON serileştirme süreci tarafından ele alınan her nesne türündeki özyineleme hakkında her şeyi bilir, ister nesne benzeri ister dizi olsun (ve her ikisini de tanımak için mantığı zaten uygular), bu nedenle bizim için her şeyi doğru şekilde işlemesi gerekir.
Jor

1
Bu çözümü çok seviyorum, çok şık ve güvenli görünüyor.
Markus

@Jor teşekkürler, bu benim için çalışıyor. Denediğim diğer parçacıklar bir şekilde başarısız oldu.
nevf

zeki! re perf: Nesnedeki her anahtar için sıralanan anahtarlar doğrusal olarak kontrol edildiğinden, bunun O (N ^ 2), N = nesnedeki sayı anahtarları olduğuna inanıyorum. Dolayısıyla performans, GHz makinelerde N> 100K civarında göze çarpan bir sorun olmaya başlayacak ve belki de N> 1 Milyon için zayıflatıcı olacak. ref: tc39.es/ecma262/#sec-json.stringify
Mike Liddell

28

Aşağıdaki ikinci argüman olarak özellik adlarının sıralı bir dizisini iletebilirsiniz JSON.stringify():

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

1
Bu davranışla ilgili belgelenmiş herhangi bir garanti var mı?
zengin remer

4
@richremer Evet, ECMAScript standardında , ikinci parametresi JSON.stringify()çağrılır replacerve bir dizi olabilir. Daha PropertyListsonra SerializeJSONObject()özellikleri bu sırayla eklemek için kullanılan bir oluşturmak için kullanılır . Bu, ECMAScript 5'ten beri belgelenmiştir.
Christian d'Heureuse

15
Obj içinde yuvalanmış nesneler varsa, yuvalanmış anahtarların ikinci bağımsız değişkende de mevcut olması gerektiğini unutmayın; aksi takdirde atılırlar! Karşı örnek: > JSON.stringify({a: {c: 1, b: 2}}, ['a']) '{"a":{}}' İlgili tüm anahtarların listesini oluşturmanın (hacky) bir yolu, nesneyi geçmek için JSON.stringify kullanmaktır: function orderedStringify(obj) { const allKeys = []; JSON.stringify(obj, (k, v) => { allKeys.push(k); return v; }); return JSON.stringify(obj, allKeys.sort()); } Örnek:> orderedStringify({a: {c: 1, b: 2}}) '{"a":{"b":2,"c":1}}'
Saif Hakim

1
Object.keys () özyinelemeli değildir . Bu, iç içe diziler veya nesneler içeren herhangi bir nesne için çalışmayacaktır.
Jor

14

2018-7-24 Güncellemesi:

Bu sürüm, yuvalanmış nesneleri sıralar ve diziyi de destekler:

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

Test durumu:

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

  });

Kullanımdan kaldırılan yanıt:

ES2016'da kısa bir versiyon. Https://stackoverflow.com/a/29622653/94148 adresinden @codename'e kredi

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

Sözdizimi tam doğru değil. Olmalı -function orderedJsonStringify(o) { return JSON.stringify(Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {})); }
Ben

Bu, şimdilik, C # DataContractJsonSerializer ve json dizesinde ilk sırada yer almayan "__type" ile ilgili sorunumu çözdü. Teşekkürler.
Yogurt The Wise

2
Bunun, Christian'ın cevabı gibi, iç içe geçmiş nesnelerde yanlış davrandığına dikkat edin.
Daniel Griscom

sortObjPropertiesByKey tanımlı değil. SortObjByKey'i mi kullanmak istediniz?
Paul Lynch

Bu sortObjByKey()döngüsel referansları kontrol ediyor gibi görünmüyor, bu yüzden dikkatli olun, giriş verilerine bağlı olarak sonsuz bir döngüde asılı kalabilir. Örnek: var objA = {}; var objB = {objA: objA}; objA.objB = objB;-> sortObjByKey(objA);->VM59:6 Uncaught RangeError: Maximum call stack size exceeded
Klesun


4

Bu Satpal Singh'in cevabıyla aynı

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

toJSONÇıktıyı özelleştirmek için kullanabileceğiniz nesnenize özel bir işlev ekleyebilirsiniz . Fonksiyonun içinde, mevcut özellikleri yeni bir nesneye belirli bir sırayla eklemek, dizilişte bu sıralamayı korumalıdır.

Buraya bakın:

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

JSON verilerine anahtarlarla erişilmesi gerektiği için sıralamayı kontrol etmek için yerleşik bir yöntem yoktur.

İşte küçük bir örnekle bir jsfiddle:

http://jsfiddle.net/Eq2Yw/

toJSONİşlevi yorumlamayı deneyin - özelliklerin sırası tersine çevrilir. Lütfen bunun tarayıcıya özel olabileceğini unutmayın, yani şartnamede sipariş resmi olarak desteklenmemektedir. Firefox'un şu anki sürümünde çalışıyor, ancak% 100 sağlam bir çözüm istiyorsanız, kendi stringifier işlevinizi yazmanız gerekebilir.

Düzenle:

Ayrıca stringify'ın deterministik olmayan çıktısıyla ilgili şu SO sorusuna, özellikle Daff'ın tarayıcı farklılıkları hakkındaki ayrıntılarına bakın:

Bir JSON nesnesinin değiştirilmediğini belirleyici olarak nasıl doğrulayabilirim?


Her nesnenin özellikleri bilinir (ve çoğunlukla dizelerdir), bu nedenle özellikleri kendi toJSON stringifier'ımda kodlamak, sıralamadan çok daha hızlı olabilir ...!
Innovine

Aşağıdaki 'sıralıJsonStringify' neredeyse çalıştı. Ama bu benim için daha iyi bir çözüm gibi görünüyor. Json dizesindeki ilk öğe olmak için C # DataContractJsonSerializer'ın '__type' ını almam gerektiğinde. var json = JSON.stringify (myjsonobj, ['__type', 'id', 'text', 'somesubobj' vb .....]); tüm anahtarları listelemek için biraz acı.
Yoğurt Arifler

3

Özyinelemeli ve basitleştirilmiş bir cevap:

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

reorderolarak yeniden adlandırılmalıdır sortObjectve bu dizileri işlemez
Jonathan Gawrych

Bunu fark ettiğiniz için teşekkürler ve OP'nin sorunu dizilere değil nesnelere başvurmaktı.
Jason Parham

@JonathanGawrych Neden dizileri sıralayasınız ki, bir sıraya sahip olmaları gerekiyor. [1,2,3] dizisi [2,3,1] dizisi ile aynı değildir, ancak bir nesnenin özellik sırası yoktur. Sorun, dizilişten sonra sıranın aniden önemli olmasıdır -% 100 eşdeğer nesneler için dizeler farklı olabilir. Maalesef deterministik bir stringify alma çabası önemli görünüyor, örnek paket: github.com/substack/json-stable-stringify/blob/master/index.js
Mörre

1
@ Mörre - Sanırım yeterince spesifik değildim. "Dizileri işlemez" derken dizilerin parçalanmış olduğunu, sıralanmamış olarak bırakılmadığını kastettim. Sorun, typeof arr === "object"dizileri nesnelere dönüştürmesidir. Örneğin var obj = {foo: ["bar", "baz"]}içine dizgelenmiş olacağını{ "foo": { "0": "bar", "1": "baz"} }
Jonathan Gawrych

if(obj.constructor.prototype !== Object.prototype)
@JonathanGawrych

3

EcmaScript 2015'te nesneyi özellik adına göre sıralayabilirsiniz

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

Belki daha iyi bir isim sortObjectPropertiesByName()veya daha basit olabilir sortPropertiesByName().
Ocak

3

Cevabı @ Jason Parham'dan aldım ve bazı iyileştirmeler yaptım

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

Bu, dizilerin nesnelere dönüştürülmesi sorununu düzeltir ve ayrıca dizilerin nasıl sıralanacağını tanımlamanıza izin verir.

Misal:

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

çıktı:

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

2

Kabul edilen yanıt, bazı nedenlerden dolayı iç içe geçmiş nesneler için benim için çalışmıyor. Bu benim kendi kodumu yazmamı sağladı. Bunu yazdığım 2019'un sonları olduğu için, dilde birkaç seçenek daha var.

Güncelleme: David Furlong'un cevabının daha önceki girişimime tercih edilen bir yaklaşım olduğuna inanıyorum ve bunu yarıda bıraktım. Benimki Object.entries (...) desteğine dayanıyor, dolayısıyla Internet Explorer desteği yok.

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

-

BU ESKİ SÜRÜMÜ TARİHSEL REFERANS İÇİN SAKLAMAK

Nesnedeki tüm anahtarların basit, düz bir dizisinin çalışacağını buldum. Neredeyse tüm tarayıcılarda (tahmin edilebileceği gibi Edge veya Internet explorer değil) ve Node 12+ Array.prototype.flatMap (...) kullanılabilir olduğu için oldukça kısa bir çözüm var. (Lodash eşdeğeri de işe yarar.) Yalnızca Safari, Chrome ve Firefox'ta test ettim, ancak flatMap ve standart JSON.stringify (...) destekleyen başka hiçbir yerde çalışmaması için hiçbir neden göremiyorum .

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

Bununla, üçüncü taraf bağımlılıkları olmadan dizgi oluşturabilir ve hatta anahtar-değer giriş çiftlerini sıralayan kendi sıralama algoritmanızı iletebilirsiniz, böylece anahtara, yüke veya ikisinin bir kombinasyonuna göre sıralayabilirsiniz. Yuvalanmış nesneler, diziler ve düz eski veri türlerinin herhangi bir karışımı için çalışır.

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

Baskılar:

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

Eski JavaScript motorlarıyla uyumluluğunuz olması gerekiyorsa flatMap davranışını taklit eden bu biraz daha ayrıntılı sürümleri kullanabilirsiniz. İstemci en az ES5'i desteklemelidir, bu nedenle Internet Explorer 8 veya altını desteklemez.

Bunlar, yukarıdakiyle aynı sonucu verecektir.

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

Lodash, iç içe geçmiş nesneler, herhangi bir nesne özelliği değeri ile çalışır:

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)

Bir nesneye atanan ilk anahtarın ilk olarak çıktısının Chrome ve Node'un davranışına dayanır JSON.stringify.


2
Teşekkürler, ama 4 yıl önce bu sorunu yaşadım, o zamandan beri biraz ilerlediğimi söylemekten mutluluk duyuyorum :)
Innovine

1
:) Bunu duymak güzel. Dün bu problemi yaşadım ve aradığım cevabı (eski ama yine de alakalı) sorunuz altında bulamadım :)
AJP

0

Deneyin:

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

Teşekkürler, ama görünüşe göre sipariş tanımlanmamış ve sadece işe yarıyor. Yine de ilginç bir yaklaşım!
Innovine

0

Nesneyi sıralamak için bir işlev yaptım ve geri aramayla .. aslında yeni bir nesne oluşturan

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

ve nesne ile çağırın.

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

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

JSON.stringify( result )

hangi yazdırır {"value":"msio","os":"windows","name":"anu"}ve değerli sıralama için.

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

JSON.stringify( result )

hangi baskılar {"os":"windows","value":"msio","name":"anu"}


1
İyi çalışıyor, ancak maalesef yinelemeli değil.
Jonathan Gawrych

0

Listedeki nesneler aynı özelliklere sahip değilse, stringify'dan önce birleştirilmiş bir ana nesne oluşturun:

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

// aşağıdaki gibi örnek. her katmanda, {} gibi nesneler için, anahtar sıralamada düzleştirilmiş. JSON.stringify gibi / ile düzleştirilmiş diziler, sayılar veya dizeler için.

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} "


Lütfen neden harici bir kütüphane kullandığınızı açıklayın ve @DeKaNszn'in dediği gibi, bazı açıklamalar ve bir giriş ekleyin. Takdir edilecektir.
Benj

bu işlev projemden kopyalanmıştır. içinde undercore.js kullanıyorum.
saintthor

0

Dizileri işlemek için AJP'nin yanıtını genişletmek:

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

Şaşırdım, kimse Lodash'ın isEqualişlevinden bahsetmedi .

Eşdeğer olup olmadıklarını belirlemek için iki değer arasında derin bir karşılaştırma yapar.

Not: Bu yöntem, dizileri, dizi arabelleklerini, boole'ları, tarih nesnelerini, hata nesnelerini, haritaları, sayıları, Nesne nesnelerini, regex'leri, kümeleri, dizeleri, sembolleri ve tiplenmiş dizileri karşılaştırmayı destekler. Nesne nesneleri, miras alınmayan, numaralandırılabilir özellikleriyle karşılaştırılır. İşlevler ve DOM düğümleri katı eşitlikle karşılaştırılır, yani ===.

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

Orijinal problemle - anahtarların tutarsız olarak sıralanması - harika bir çözüm - ve elbette tüm nesneyi körü körüne serileştirmek yerine bir çatışma bulursa durur.

Tüm kitaplığı içe aktarmaktan kaçınmak için şunu yapın:

import { isEqual } from "lodash-es";

Bonus örnek: Bunu, bu özel operatörle RxJS ile de kullanabilirsiniz.

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

0

Sonuçta, iç içe geçmiş nesnedeki tüm anahtarları önbelleğe alan bir Diziye ihtiyacı vardır (aksi takdirde önbelleğe alınmamış anahtarları atlar.) En eski cevap tamamen yanlıştır, çünkü ikinci argüman noktalı notasyonu umursamaz. Böylece cevap (Set kullanarak) olur.

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

İşte bir klon yaklaşımı ... json'a dönüştürmeden önce nesneyi klonlayın:

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

Çok yeniyse ancak package.json dosyalarında çalışıyor gibi görünüyor.


-3

Size Array.sortyardımcı olabilecek bir yöntem var. Örneğin:

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

1
Yine de diziyi sıralamak istemiyorum. Aslında dizi kısmı önemli değil .. Bir nesnenin özelliklerini sıralamak istiyorum .. birkaç hızlı deneyden, özellikler oluşturuldukları sırayla listelenmiş gibi görünüyor. Bunun bir yolu, yeni bir nesne oluşturmak ve özellikleri alfabetik sırayla kopyalamak olabilir, ancak daha kolay / daha hızlı bir şey olmasını umuyorum ..
Innovine

1
@Innovine, bu bile işe yaramaz, çünkü anahtarların spesifikasyona göre oluşturma zamanına göre sipariş edilmesi garanti edilmez.
Dogbert

Sonra soru şu oluyor: Anahtarlar sabit bir sırayla olacak şekilde nesnelerimi nasıl dizgeleştirebilirim .. (key in obj) için yapmam ve onları geçici bir dizide saklamam ve bunu ve manuel olarak sıralamam imkansız değil bir ip oluşturun .. ama umutsuzca daha kolay bir yol olduğunu umuyorum
Innovine

Hayır, hemen hemen bunu yapmanın yolu bu. JavaScript’e hoş geldiniz.
marksyzm
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.