[javascript] 객체 속성 및 JSON.stringify 정렬

내 응용 프로그램에는 많은 객체가 있으며,이를 문자열 화하여 디스크에 저장합니다. 불행히도 배열의 객체가 조작되고 때때로 교체 될 때 객체의 속성은 다른 순서 (생성 순서?)로 나열됩니다. 배열에서 JSON.stringify ()를 수행하고 저장하면 diff는 속성이 다른 순서로 나열되는 것을 보여줍니다. 이는 diff 및 병합 도구를 사용하여 데이터를 더 병합하려고 할 때 성가신 일입니다.

이상적으로는 stringify를 수행하기 전에 또는 stringify 작업의 일부로 객체의 속성을 알파벳 순서로 정렬하고 싶습니다. 많은 곳에서 배열 객체를 조작하는 코드가 있으며 항상 명시적인 순서로 속성을 생성하도록 변경하는 것은 어려울 수 있습니다.

제안을 가장 환영합니다!

요약 된 예 :

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

이 두 stringify 호출의 출력은 다르며 내 데이터의 차이에 표시되지만 내 응용 프로그램은 속성의 순서를 신경 쓰지 않습니다. 개체는 여러 방법과 장소에서 구성됩니다.



답변

더 간단하고 현대적이며 현재 브라우저에서 지원하는 접근 방식은 다음과 같습니다.

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

그러나이 메서드는 참조되지 않고 배열 내의 개체에 적용되지 않는 중첩 된 개체를 제거합니다. 다음 출력과 같은 것을 원한다면 정렬 개체도 평평하게 만들고 싶을 것입니다.

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

다음과 같이 할 수 있습니다.

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

직접 조정할 수있는 작업을 프로그래밍 방식으로 수행하려면 개체 속성 이름을 배열에 넣은 다음 배열을 알파벳순으로 정렬하고 해당 배열을 반복 (올바른 순서로 표시)하고 개체에서 각 값을 선택해야합니다. 그 순서. “hasOwnProperty”도 선택되어 있으므로 확실히 개체의 고유 속성 만 있습니다. 예를 들면 다음과 같습니다.

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

다시 말하지만 이렇게하면 알파벳 순서로 반복 할 수 있습니다.

마지막으로, 가장 간단한 방법으로 더 나아가이 라이브러리를 사용하면 전달하는 JSON을 재귀 적으로 정렬 할 수 있습니다. 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));

산출

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


답변

나는 당신이 JSON 생성을 제어하고 있다면 (그리고 당신처럼 들린다) 당신의 목적을 위해 이것은 좋은 해결책이 될 것이라고 생각합니다 : json-stable-stringify

프로젝트 웹 사이트에서 :

문자열 화 된 결과에서 결정적 해시를 얻기 위해 사용자 정의 정렬을 사용하는 결정적 JSON.stringify ()

생성 된 JSON이 결정적이라면 쉽게 비교 / 병합 할 수 있어야합니다.


답변

정렬 된 속성 이름 배열을의 두 번째 인수로 전달할 수 있습니다 JSON.stringify().

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


답변

모든 키를 재귀 적으로 가져 오기 위해 현재 베스트 답변의 복잡성이 필요한 이유를 이해할 수 없습니다. 완벽한 성능이 필요하지 않는 한 JSON.stringify(), 처음에는 모든 키를 얻기 위해 두 번 전화를 걸 수 있고, 두 번째로 실제로 작업을 수행 할 수있는 것 같습니다. 그런 식으로 모든 재귀 복잡성은에 의해 처리되고 stringify우리는 그것이 그 내용과 각 객체 유형을 처리하는 방법을 알고 있음을 압니다.

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


답변

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


답변

https://gist.github.com/davidfurlong/463a83a33b70a3b6618e97ec9679e490

const replacer = (key, value) =>
    value instanceof Object && !(value instanceof Array) ?
        Object.keys(value)
        .sort()
        .reduce((sorted, key) => {
            sorted[key] = value[key];
            return sorted
        }, {}) :
        value;


답변

이것은 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"}"