[javascript] 순환 객체 값을 포함하는 직렬화 객체

다른 노드에 대한 참조 인 하위 노드가 포함 된 객체 (구문 트리)가 있습니다.

내가 사용하는,이 객체를 직렬화하고 싶습니다 JSON.stringify(),하지만 난 얻을

TypeError : 순환 객체 값

내가 언급 한 구성 때문에

이 문제를 어떻게 해결할 수 있습니까? 다른 노드에 대한 이러한 참조가 직렬화 된 오브젝트에 표시되는지 여부는 중요하지 않습니다.

반면에 객체를 만들 때 객체에서 이러한 속성을 제거하는 것은 지루한 것처럼 보이고 파서 (수선화)를 변경하고 싶지 않습니다.



답변

이미 직렬화 된 객체를 제외 시키 stringify려면 replacer 함수 의 두 번째 매개 변수를 사용하십시오 .

var seen = [];

JSON.stringify(obj, function(key, val) {
   if (val != null && typeof val == "object") {
        if (seen.indexOf(val) >= 0) {
            return;
        }
        seen.push(val);
    }
    return val;
});

http://jsfiddle.net/mH6cJ/38/

다른 주석에서 올바르게 지적했듯이이 코드는 “재귀 적”객체뿐만 아니라 모든 “본”객체를 제거합니다.

예를 들면 다음과 같습니다.

a = {x:1};
obj = [a, a];

결과가 올바르지 않습니다. 구조가 이와 같으면 Crockford의 decycle 또는 재귀 참조를 null로 대체하는이 (간단한) 함수 를 사용할 수 있습니다 .

function decycle(obj, stack = []) {
    if (!obj || typeof obj !== 'object')
        return obj;

    if (stack.includes(obj))
        return null;

    let s = stack.concat([obj]);

    return Array.isArray(obj)
        ? obj.map(x => decycle(x, s))
        : Object.fromEntries(
            Object.entries(obj)
                .map(([k, v]) => [k, decycle(v, s)]));
}

//

let a = {b: [1, 2, 3]}
a.b.push(a);

console.log(JSON.stringify(decycle(a)))


답변

순환 구조를 감지하고 해독 및 인코딩 할 수있는 GitHub Gist를 만들었습니다 : https://gist.github.com/Hoff97/9842228

변환하려면 JSONE.stringify / JSONE.parse를 사용하십시오. 또한 함수를 해독하고 인코딩합니다. 이것을 사용하지 않으려면 32-48 및 61-85 행을 제거하십시오.

var strg = JSONE.stringify(cyclicObject);
var cycObject = JSONE.parse(strg);

여기에서 바이올린 예제를 찾을 수 있습니다.

http://jsfiddle.net/hoff97/7UYd4/


답변

이것은 대체 대답의 일종이지만 많은 사람들이 여기에 오는 것은 원형 객체를 디버깅하는 것이므로 많은 코드를 가져 오지 않고 실제로 수행 할 수있는 좋은 방법은 없습니다.

잘 알려지지 않은 기능 중 하나 JSON.stringify()입니다 console.table(). 간단히 호출 console.table(whatever);하면 콘솔에 변수를 표 형식으로 기록하므로 변수 내용을 쉽게 이해할 수 있습니다.


답변

어디서 많이 보호기 그것은 보여 주기 객체가 있었다.

<script>
var jsonify=function(o){
    var seen=[];
    var jso=JSON.stringify(o, function(k,v){
        if (typeof v =='object') {
            if ( !seen.indexOf(v) ) { return '__cycle__'; }
            seen.push(v);
        } return v;
    });
    return jso;
};
var obj={
    g:{
        d:[2,5],
        j:2
    },
    e:10
};
obj.someloopshere = [
    obj.g,
    obj,
    { a: [ obj.e, obj ] }
];
console.log('jsonify=',jsonify(obj));
</script>

생산

jsonify = {"g":{"d":[2,5],"j":2},"e":10,"someloopshere":[{"d":[2,5],"j":2},"__cycle__",{"a":[10,"__cycle__"]}]}


답변

순환 객체를 직렬화하고 String과 같은 serializename 속성에 클래스를 저장하면 클래스를 복원 할 수있는 github 프로젝트를 너무 만듭니다.

var d={}
var a = {b:25,c:6,enfant:d};
d.papa=a;
var b = serializeObjet(a);
assert.equal(  b, "{0:{b:25,c:6,enfant:'tab[1]'},1:{papa:'tab[0]'}}" );
var retCaseDep = parseChaine(b)
assert.equal(  retCaseDep.b, 25 );
assert.equal(  retCaseDep.enfant.papa, retCaseDep );

https://github.com/bormat/serializeStringifyParseCyclicObject

편집 : NPM https://github.com/bormat/borto_circular_serialize에 대한 스크립트를 변환 했으며 함수 이름을 프랑스어에서 영어로 변경했습니다.


답변

순환 참조가있는 데이터 구조의 예는 다음과 같습니다.
공구 창고

function makeToolshed(){
    var nut = {name: 'nut'}, bolt = {name: 'bolt'};
    nut.needs = bolt; bolt.needs = nut;
    return { nut: nut, bolt: bolt };
}

순환 참조 ( KEEP)유지 하려면 ( “핵심”대신에 역 직렬화 할 때 복원) 두 가지 중에서 선택할 수 있습니다. 여기에서 비교하겠습니다. 첫 번째는 Douglas Crockford의 cycle.js 이고 두 번째는 내 시베리아 패키지입니다. 둘 다 먼저 객체를 “재순환”하여 (즉, 동일한 정보를 포함하는 다른 순환 참조없이) 다른 객체를 구성합니다.

Crockford 씨가 먼저갑니다 :

JSON.decycle(makeToolshed())

JSON_decycleMakeToolshed

보시다시피 JSON의 중첩 구조는 유지되지만 특별한 $ref속성을 가진 객체 인 새로운 것이 있습니다. 그것이 어떻게 작동하는지 봅시다.

root = makeToolshed();
[root.bolt === root.nut.needs, root.nut.needs.needs === root.nut]; // retutrns [true,true]

달러 기호는 루트를 나타냅니다. .bolt있는 것은 $ref라고 우리에게 이야기 .bolt에 “이미 본”개체이며, 먼저 볼 경우 특별한 속성의 값이 (여기에서, 문자열 $ [ “너트”] [ “필요”]) 우리에게 ===위. 두 번째 $ref와 두 번째도 마찬가지입니다 ===.

복제가 작동하는지 확인 하기 위해 적절한 심도 평등 테스트 (즉, 이 질문에 대한deepGraphEqual 답변에서 Anders Kaseorg의 기능 )를 사용하십시오.

root = makeToolshed();
clone = JSON.retrocycle(JSON.decycle(root));
deepGraphEqual(root, clone) // true
serialized = JSON.stringify(JSON.decycle(root));
clone2 = JSON.retrocycle(JSON.parse(serialized));
deepGraphEqual(root, clone2); // true

시베리아

JSON.Siberia.forestify(makeToolshed())

JSON_Siberia_forestify_make 도구

시베리아는 “클래식”JSON을 모방하려고 시도하지 않고 중첩 구조를 사용하지 않습니다. 객체 그래프는 “평평한”방식으로 설명됩니다. 객체 그래프의 각 노드는 플랫 트리 (정수 전용 값을 갖는 일반 키 값 쌍 목록)로 바뀝니다 .forest.. 인덱스 0 의 항목 은 루트 객체를 찾고 높은 지수에서는 다른 노드를 찾습니다. 개체 그래프와 (포리스트 트리의 일부 키에 대한 음수 값)은 atoms배열을 가리 킵니다 (유형 배열을 통해 입력되지만 여기서는 입력 세부 정보를 건너 뜁니다). 모든 터미널 노드는 원자 테이블에 있고 모든 비 터미널 노드는 포리스트 테이블에 있으며 개체 그래프에있는 노드 수를 즉시 확인할 수 있습니다 forest.length. 작동하는지 테스트 해 봅시다.

root = makeToolshed();
clone = JSON.Siberia.unforestify(JSON.Siberia.forestify(root));
deepGraphEqual(root, clone); // true
serialized = JSON.Siberia.stringify(JSON.Siberia.forestify(root));
clone2 = JSON.Siberia.unforestify(JSON.Siberia.unstringify(serialized));
deepGraphEqual(root, clone2); // true

비교

나중에 섹션을 추가합니다.


답변

function stringifyObject ( obj ) {
  if ( _.isArray( obj ) || !_.isObject( obj ) ) {
    return obj.toString()
  }
  var seen = [];
  return JSON.stringify(
    obj,
    function( key, val ) {
      if (val != null && typeof val == "object") {
        if ( seen.indexOf( val ) >= 0 )
          return
          seen.push( val )
          }
      return val
    }
  );
}

전제 조건이 누락되었습니다. 그렇지 않으면 배열 객체의 정수 값이 잘립니다. 즉 [[08.11.2014 12:30:13, 1095]] 1095가 095로 줄어 듭니다.