객체 속성 및 JSON.stringify 정렬


101

내 응용 프로그램에는 많은 객체가 있으며,이를 문자열 화하여 디스크에 저장합니다. 불행히도 배열의 객체가 조작되고 때때로 교체 될 때 객체의 속성은 다른 순서 (생성 순서?)로 나열됩니다. 배열에서 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 출력 또는 JS 객체 리터럴)
Bojangles

4
개체의 개체 키는 고정 된 순서를 보장하지 않습니다. 이것은 의도적으로 설계된 것입니다.
Passerby 2013


1
@rab, 어디서 알아 냈어? 참고 : 작동 할 수 있지만 (아마도 대부분의 경우 작동 함) 보장되지는 않습니다.
Dogbert 2013-04-23

1
여기 OP. 여기에는 속성 순서에 대한 종속성이 없었으며 직렬화 된 데이터에서 diff를 피하는 방법에 대한 질문 일뿐입니다. 이것은 결국 아래의 대답에서와 같이 배열에 속성을 숨기고 직렬화 전에 정렬하여 해결되었습니다.
Innovine

답변:


78

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

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}

9
이것은 내가 피하려고 한 것입니다 :) 그러나 감사합니다. 무거운 경우 올바른 해결책처럼 보입니다.
Innovine 2013-04-23

1
이 코드에 버그가 있습니다. 는 정수 obj[i]이기 때문에 for 루프에서 참조 할 수 없으며 i속성 이름이 반드시 필요한 것은 아닙니다 (따라서이 질문). 이어야합니다 obj[arr[i]].
Andrew Ensley 2013-06-19

1
콜백은 비동기 동작에만 국한되지 않습니다.
marksyzm

2
@Johann 여기서 콜백을 사용함으로써 그는 iterateObjectAlphabetically재사용 가능한 함수로 변 합니다. 콜백이 없으면 '페이로드 코드'가 함수 내부에 있어야합니다. 매우 우아한 솔루션이며 많은 라이브러리와 JS 코어 자체에서 사용되는 솔루션이라고 생각합니다. 예 : Array.forEach .
Stijn de Witt 2015 년

1
@marksyzm 괜찮습니다. 제 경우에는 선택한 필드 만 문자열 화해야했습니다. 따라서 당신의 대답은 나를 길로 인도했습니다. 감사합니다
Benj

39

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

프로젝트 웹 사이트에서 :

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

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


저장소의 상태가 좋지 않습니다. 3 년 동안 업데이트되지 않았으며 해결되지 않은 문제와 풀 요청이 있습니다. 새로운 답변을 찾는 것이 더 낫다고 생각합니다.
Tom

3
@Tom 또한 리포지토리에는 매주 다운로드 (!)가 5 백만 회 있습니다. 즉, 적극적으로 사용되고 있습니다. '해결되지 않은'미해결 문제 및 / 또는 끌어 오기 요청이 있다는 것은 그다지 의미가 없습니다. 저자가 이러한 문제에 대해 신경 쓰지 않거나 시간이 없다는 점만 알 수 있습니다. 모든 lib가 몇 달마다 업데이트 될 필요는 없습니다. 사실, imho, 최고의 libs는 매우 드물게 업데이트를받습니다. 무언가가 완료되면 완료됩니다. 이 프로젝트에 실제 문제가 없다고 말하는 것은 아니지만 그렇다면 그 점을 지적하십시오. 나는이 lib BTW와 관련이 없습니다.
Stijn de Witt

ES6 지정된대로 (배열이 아닌) 객체를 정렬 할 수 있다는 것이 망가진 것 같습니다. 사용자 편집을 위해 필요합니다. 순서는 컴퓨터에 상관 없습니다. 편집하는 사용자에게 적용됩니다. 시도해 볼 가치가있었습니다.
TamusJRoyce 19

1
@Tom이 말하는 것 외에도이 프로젝트에는 런타임 종속성이 없음을 지적합니다. 즉,이 저장소에 보안 / 유지 관리 문제가없는 경우 사용하기에 상당히 안정적이고 안전합니다. 또한 ES6로 테스트했는데 (적어도 Firefox에서는) 잘 작동하는 것 같습니다.
Phil

28

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

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

1
이 동작에 대한 문서화 된 보증이 있습니까?
rich remer

4
@richremer 예, ECMAScript 표준 에서는의 두 번째 매개 변수 JSON.stringify()가 호출 replacer되며 배열이 될 수 있습니다. 이 순서대로 속성을 추가하는 PropertyList데 사용되는을 빌드하는 데 사용됩니다 SerializeJSONObject(). 이것은 ECMAScript 5 이후 문서화되었습니다.
Christian d' Heureuse

15
obj에 중첩 된 객체가있는 경우 중첩 된 키는 두 번째 인수에도 있어야합니다. 그렇지 않으면 삭제됩니다! 반대 예 : > JSON.stringify({a: {c: 1, b: 2}}, ['a']) '{"a":{}}' 모든 관련 키 목록을 작성하는 한 가지 (해키) 방법은 JSON.stringify를 사용하여 객체를 탐색하는 것입니다. function orderedStringify(obj) { const allKeys = []; JSON.stringify(obj, (k, v) => { allKeys.push(k); return v; }); return JSON.stringify(obj, allKeys.sort()); } 예 :> orderedStringify({a: {c: 1, b: 2}}) '{"a":{"b":2,"c":1}}'
Saif Hakim

1
Object.keys ()는 재귀 적이 지 않습니다 . 중첩 된 배열 또는 개체를 포함하는 개체에 대해서는 작동하지 않습니다.
Jor

27

모든 키를 재귀 적으로 가져 오기 위해 현재 베스트 답변의 복잡성이 필요한 이유를 이해할 수 없습니다. 완벽한 성능이 필요하지 않는 한 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 );
}

흥미롭지 만 실제로 stringify를 사용하여 모든 키를 배열에 매핑하는 "속임수"를 사용했습니다. 그 배열은 더 쉽게 할 수 있고 안전은 Object.keys를 통해 얻을
베르나르도 달 Corno에게

5
아니요, 요점은 Object.keys()재귀 적이 지 않으므로 같은 객체가 {a: "A", b: {c: "C"} }있고 Object.keys를 호출하면 a및 키만 얻을 수 b있지만 c. JSON.stringifyJSON 직렬화 프로세스에 의해 처리되는 모든 객체 유형의 재귀에 대한 모든 것을 알고 있습니다. 객체와 유사하거나 배열 (이미 둘 다 인식하는 논리를 이미 구현하고 있음) 등 모든 것을 올바르게 처리해야합니다.
Jor dec.

1
이 솔루션을 사랑하고, 매우 우아하고 안전합니다.
Markus

@Jor 감사합니다. 내가 시도한 다른 스 니펫은 어떤 식 으로든 실패했습니다.
nevf

14

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

구문이 옳지 않습니다. 해야 -function orderedJsonStringify(o) { return JSON.stringify(Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {})); }

현재로서는 C # DataContractJsonSerializer 및 "__type"이 json 문자열에서 먼저 나열되지 않는 문제를 해결했습니다. 감사.
Yogurt The Wise

2
이것은 Christian의 대답과 마찬가지로 중첩 된 개체에서 잘못 작동합니다.
Daniel Griscom nov

sortObjPropertiesByKey가 정의되지 않았습니다. sortObjByKey를 사용하려고 했습니까?
Paul Lynch

이것은 sortObjByKey()순환 참조를 확인 하지 않는 것 같으므로 입력 데이터에 따라 무한 루프에서 멈출 수 있으므로주의하십시오. 예 : var objA = {}; var objB = {objA: objA}; objA.objB = objB;-> sortObjByKey(objA);->VM59:6 Uncaught RangeError: Maximum call stack size exceeded
Klesun


4

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

사용자 정의를 추가 할 수 있습니다. 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의 비 결정적 출력, 특히 브라우저 차이점에 대한 Daff의 세부 정보에 관한이 SO 질문을 참조하십시오.

JSON 객체가 수정되지 않았는지 결정적으로 확인하는 방법은 무엇입니까?


각 객체의 속성은 알려져 있으므로 (대부분 문자열) 내 자신의 toJSON stringifier에서 속성을 하드 코딩하는 것이 정렬보다 훨씬 빠를 수 있습니다 ...!
Innovine 2013-04-23

아래의 'OrderedJsonStringify'는 거의 작동했습니다. 그러나 이것은 나에게 더 나은 해결책으로 보입니다. C # DataContractJsonSerializer의 '__type'을 json 문자열의 첫 번째 항목으로 가져와야 할 때. var json = JSON.stringify (myjsonobj, [ '__type', 'id', 'text', 'somesubobj'etc .....]); 모든 키를 나열하는 데 약간의 고통이 있습니다.
Yogurt The Wise

3

재귀적이고 단순화 된 대답 :

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

reorder로 이름을 바꿔야하며 sortObject이것은 배열을 처리하지 않습니다
Jonathan Gawrych 2015

알아 주셔서 감사합니다. OP의 문제는 배열이 아닌 객체를 사용하는 것이 었습니다.
Jason Parham

@JonathanGawrych 어쨌든 배열을 정렬하는 이유는 순서가 있어야합니다. 배열 [1,2,3]은 배열 [2,3,1]과 동일하지 않지만 객체에는 속성 순서가 없습니다. 문제는 문자열 화 후에 갑자기 순서가 중요하다는 것입니다. 100 % 동등한 객체의 문자열은 다를 수 있습니다. 불행히도 결정 론적 stringify를 얻기위한 노력은 상당한 것 같습니다. 예제 패키지 : github.com/substack/json-stable-stringify/blob/master/index.js
Mörre

1
@ Mörre-내가 충분히 구체적이지 않은 것 같아요. "배열을 처리하지 않는다"는 것은 배열이 정렬되지 않은 상태로 남아 있지 않고 손상되었음을 의미합니다. 문제는 typeof arr === "object"배열을 객체로 변환 하기 때문입니다. 예를 들어 var obj = {foo: ["bar", "baz"]}으로도 캐릭터 라인 될 것입니다{ "foo": { "0": "bar", "1": "baz"} }
조나단 Gawrych

: @JonathanGawrych에 의해 발견 된 문제를 해결하기 위해if(obj.constructor.prototype !== Object.prototype)
ricka

3

EcmaScript 2015에서 속성 이름으로 개체를 정렬 할 수 있습니다.

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

더 나은 이름이 sortObjectPropertiesByName()더 간단 할 수도 있습니다 sortPropertiesByName().
1

3

@Jason Parham의 답변을 받아 몇 가지 개선했습니다.

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

이렇게하면 배열이 객체로 변환되는 문제가 해결되고 배열 정렬 방법을 정의 할 수도 있습니다.

예:

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

산출:

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

2

어떤 이유로 든 중첩 된 개체에 대해 허용 된 답변이 작동하지 않습니다. 이로 인해 내 자신의 코드를 작성하게되었습니다. 이 글을 쓰는 2019 년 말이 되었기 때문에 언어 내에서 사용할 수있는 옵션이 몇 가지 더 있습니다.

업데이트 : 나는 David Furlong의 대답 이 나의 이전 시도에 대한 바람직한 접근 방식 이라고 믿습니다 . Mine은 Object.entries (...) 지원에 의존하므로 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);

-

역사적 참조를 위해이 이전 버전 유지

객체에있는 모든 키의 단순하고 평평한 배열이 작동한다는 것을 알았습니다. 거의 모든 브라우저 (예상대로 Edge 또는 Internet Explorer가 아님) 및 Node 12+에는 Array.prototype.flatMap (...) 을 사용할 수 있는 매우 짧은 솔루션 이 있습니다. (lodash 등가물도 작동합니다.) Safari, Chrome 및 Firefox에서만 테스트했지만 flatMap 및 표준 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);
}

이를 통해 타사 종속성없이 문자열화할 수 있으며 키-값 항목 쌍을 정렬하는 자체 정렬 알고리즘을 전달할 수도 있으므로 키, 페이로드 또는이 둘의 조합을 기준으로 정렬 할 수 있습니다. 중첩 된 개체, 배열 및 일반 이전 데이터 유형의 혼합에 대해 작동합니다.

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

인쇄물:

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

이전 JavaScript 엔진과 호환되어야하는 경우 flatMap 동작을 에뮬레이트하는 약간 더 자세한 버전을 사용할 수 있습니다. 클라이언트는 최소한 ES5를 지원해야하므로 Internet Explorer 8 이하는 지원되지 않습니다.

위와 같은 결과가 반환됩니다.

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, 중첩 된 개체, 개체 속성의 모든 값과 함께 작동합니다.

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)

객체에 할당 된 첫 번째 키가 .NET에서 먼저 출력되는 것은 Chrome 및 Node의 동작에 의존합니다 JSON.stringify.


2
감사합니다,하지만 난 4 년 전에이 문제를 가지고 있었다, 나는 :) 그 이후 비트를 이동 한 말을 행복 해요
Innovine

1
:) 듣기 좋습니다. 어제이 문제가 있었지만 (오래되었지만 여전히 관련성이있는) 질문에서 내가 찾고 있던 답을 찾지 못했지만 :)
AJP

0

시험:

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

감사합니다.하지만 분명히 주문이 정의되지 않았고 작동합니다. 그래도 흥미로운 접근 방식!
Innovine 2013-04-23

0

객체를 정렬하는 함수를 만들었고 실제로 새 객체를 만드는 callback ..

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

object로 호출합니다.

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

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

JSON.stringify( result )

인쇄 {"value":"msio","os":"windows","name":"anu"}하고 값으로 정렬합니다.

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

JSON.stringify( result )

어느 인쇄 {"os":"windows","value":"msio","name":"anu"}


1
잘 작동하지만 불행히도 재귀 적이 지 않습니다.
Jonathan Gawrych 2015

0

목록의 객체에 동일한 속성이 없으면 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 );
}

// 예제는 아래와 같습니다. 각 레이어에서 {}와 같은 객체의 경우 키 정렬로 병합됩니다. 배열, 숫자 또는 문자열의 경우 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} "


외부 lib를 사용하는 이유를 설명하고 @DeKaNszn이 말했듯이 몇 가지 설명과 소개를 추가하십시오. 감사하겠습니다.
Benj

이 기능은 내 프로젝트에서 복사됩니다. 내가 underscore.js를 사용합니다.
saintthor

0

AJP의 대답을 확장하여 배열을 처리합니다.

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

놀랍게도 아무도 lodash의 isEqual기능 을 언급하지 않았습니다 .

두 값을 자세히 비교하여 동일한 지 확인합니다.

참고 :이 메서드는 배열, 배열 버퍼, 부울, 날짜 개체, 오류 개체, 맵, 숫자, 개체 개체, 정규식, 집합, 문자열, 기호 및 형식화 된 배열 비교를 지원합니다. 개체 개체는 상속되지 않고 열거 가능한 속성으로 비교됩니다. 함수와 DOM 노드는 완전 동등성 (예 : ===)으로 비교됩니다.

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

원래의 문제 (키 순서가 일관되지 않음)는 훌륭한 솔루션입니다. 물론 전체 객체를 맹목적으로 직렬화하는 대신 충돌이 발견되면 중지됩니다.

전체 라이브러리를 가져 오지 않으려면 다음을 수행하십시오.

import { isEqual } from "lodash-es";

보너스 예 :이 사용자 지정 연산자를 사용하여 RxJS와 함께 사용할 수도 있습니다.

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

0

결국, 중첩 된 객체의 모든 키를 캐시하는 배열이 필요합니다 (그렇지 않으면 캐시되지 않은 키를 생략합니다.) 두 번째 인수는 점 표기법을 고려하지 않기 때문에 가장 오래된 대답은 잘못된 것입니다. 그래서 답은 (Set 사용)이됩니다.

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

다음은 복제 접근 방식입니다 ... 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;
}

매우 새롭지 만 package.json 파일에서 잘 작동하는 것 같습니다.


-3

Array.sort당신을 위해 도움이 될 수있는 방법은. 예를 들면 :

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

1
그래도 배열을 정렬하고 싶지 않습니다. 사실 배열 부분은 중요하지 않습니다. 객체의 속성을 정렬하고 싶습니다. 몇 가지 간단한 실험에서 속성이 생성 된 순서대로 나열되는 것처럼 보입니다. 한 가지 방법은 새 개체를 만들고 속성을 알파벳 순서로 복사하는 것이지만 더 쉽고 빠른 것이 있기를 바랍니다.
Innovine

1
@Innovine, 그것조차도 키가 사양에 의해 생성 시간에 의해 순서가 보장되지 않기 때문에 작동하지 않습니다.
Dogbert 2013-04-23

그런 다음 질문은 키가 고정 된 순서로되어있는 방식으로 객체를 어떻게 문자열 화합니까?입니다. (obj의 키)를 위해 수행하고 임시 배열에 저장하고 정렬하고 수동으로 정렬하는 것은 불가능하지 않습니다. 문자열을 구성 ..하지만 난 필사적으로 쉬운 방법이 바라고 있어요
Innovine

아뇨, 그렇게하는 방법입니다. JavaScript에 오신 것을 환영합니다.
marksyzm 2011
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.