133

私のアプリケーションには多数のオブジェクトがあり、それらを文字列化してディスクに保存しています。残念ながら、配列内のオブジェクトが操作され、場合によっては置き換えられると、オブジェクトのプロパティは異なる順序 (作成順序?) でリストされます。配列で JSON.stringify() を実行して保存すると、プロパティが異なる順序でリストされていることが差分に表示されます。これは、差分およびマージ ツールを使用してデータをさらにマージしようとするときに面倒です。

理想的には、文字列化を実行する前に、または文字列化操作の一部として、オブジェクトのプロパティをアルファベット順にソートしたいと考えています。多くの場所で配列オブジェクトを操作するためのコードがあり、これらを変更して常に明示的な順序でプロパティを作成するのは困難です。

提案は大歓迎です!

凝縮された例:

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

これら 2 つの stringify 呼び出しの出力は異なり、データの差分に表示されますが、アプリケーションはプロパティの順序を気にしません。オブジェクトは、さまざまな方法と場所で構築されます。

4

24 に答える 24

42

あなたがJSON生成を管理している場合(そしてあなたのように聞こえます)、あなたの目的のためにこれは良い解決策かもしれません:json-stable-stringify

プロジェクトのウェブサイトから:

文字列化された結果から決定論的なハッシュを取得するためのカスタムソートを使用した決定論的な JSON.stringify()

生成された JSON が決定論的である場合、簡単に差分/マージできるはずです。

于 2014-01-21T19:21:04.280 に答える
15

2018 年 7 月 24 日更新:

このバージョンはネストされたオブジェクトをソートし、配列もサポートします:

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

テストケース:

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

  });

非推奨の回答:

ES2016 の簡潔なバージョン。https://stackoverflow.com/a/29622653/94148からの @codename へのクレジット

function orderedJsonStringify(o) {
  return JSON.stringify(Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {}));
}
于 2016-03-05T06:33:39.403 に答える
4

再帰的で単純化された答え:

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);
于 2015-02-17T16:00:10.390 に答える
4

EcmaScript 2015 では、オブジェクトをプロパティ名で並べ替えることができます

function sortObjectByPropertyName(obj) {
    return Object.keys(obj).sort().reduce((c, d) => (c[d] = obj[d], c), {});
}
于 2016-03-05T06:48:10.920 に答える
3

toJSON出力をカスタマイズするために使用できるカスタム関数をオブジェクトに追加できます。関数内で、現在のプロパティを特定の順序で新しいオブジェクトに追加すると、文字列化されたときにその順序が保持されます。

ここを参照してください:

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

JSON データはキーによってアクセスされることを意図しているため、順序を制御する組み込みの方法はありません。

小さな例を含む jsfiddle を次に示します。

http://jsfiddle.net/Eq2Yw/

関数をコメントアウトしてみてくださいtoJSON- プロパティの順序が逆になっています。これはブラウザ固有のものである可能性があることに注意してください。つまり、順序付けは仕様で正式にサポートされていません。現在のバージョンの Firefox で動作しますが、100% 堅牢なソリューションが必要な場合は、独自の stringifier 関数を作成する必要がある場合があります。

編集:

stringify の非決定論的出力に関するこの SO の質問、特にブラウザーの違いに関する Daff の詳細も参照してください。

JSONオブジェクトが変更されていないことを決定論的に検証する方法は?

于 2013-04-23T11:25:28.167 に答える
1

lodash、ネストされたオブジェクト、オブジェクト属性の任意の値で動作します:

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)

オブジェクトに割り当てられた最初のキーが によって最初に出力されるという Chrome と Node の動作に依存していますJSON.stringify

于 2017-08-07T15:02:43.367 に答える
-4

あなたに役立つ方法がありArray.sortます。例えば:

yourBigArray.sort(function(a,b){
    //custom sorting mechanism
});
于 2013-04-23T11:04:05.250 に答える