순환 참조를 사용하여 JavaScript 객체 문자열 화 (JSON으로 변환)


79

순환 참조가 포함 된 JavaScript 개체 정의가 있습니다. 부모 개체를 참조하는 속성이 있습니다.

또한 서버로 전달하고 싶지 않은 기능도 있습니다. 이러한 개체를 직렬화 및 역 직렬화하려면 어떻게해야합니까?

이 작업을 수행하는 가장 좋은 방법은 Douglas Crockford의 stringify를 사용하는 것이라고 읽었습니다. 그러나 Chrome에서 다음 오류가 발생합니다.

TypeError : 원형 구조를 JSON으로 변환

코드:

function finger(xid, xparent){
    this.id = xid;
    this.xparent;
    //other attributes
}

function arm(xid, xparent){
    this.id = xid;
    this.parent = xparent;
    this.fingers = [];

    //other attributes

    this.moveArm = function() {
        //moveArm function details - not included in this testcase
        alert("moveArm Executed");
    }
}

 function person(xid, xparent, xname){
    this.id = xid;
    this.parent = xparent;
    this.name = xname
    this.arms = []

    this.createArms = function () {
        this.arms[this.arms.length] = new arm(this.id, this);
    }
}

function group(xid, xparent){
    this.id = xid;
    this.parent = xparent;
    this.people = [];
    that = this;

    this.createPerson = function () {
        this.people[this.people.length] = new person(this.people.length, this, "someName");
        //other commands
    }

    this.saveGroup = function () {
        alert(JSON.stringify(that.people));
    }
}

이 질문을 위해 만든 테스트 케이스입니다. 이 코드에는 오류가 있지만 기본적으로 개체 내에 개체가 있으며 개체가 생성 될 때 부모 개체가 무엇인지 보여주기 위해 각 개체에 참조가 전달됩니다. 각 개체에는 함수가 포함되어 있는데,이 기능은 문자열 화하고 싶지 않습니다. 나는 단지 Person.Name.

서버로 보내기 전에 직렬화하고 동일한 JSON이 다시 전달되었다고 가정하여 직렬화를 해제하는 방법은 무엇입니까?



크록 포드는 사용하는 것 자신의 cycle.js을 로 replacer당신의 stringify전화 로 @MattEvans는 지적 아래,.
— ruffin

답변:


113

원형 구조 오류는 객체 자체 인 객체의 속성이 직접 ( a -> a) 또는 간접 ( a -> b -> a) 인 경우 발생합니다.

오류 메시지를 피하려면 순환 참조를 만났을 때 수행 할 작업을 JSON.stringify에 알려주십시오. 예를 들어, 원래 사람을 가리킬 수 있거나 가리킬 수없는 다른 사람 ( "부모")을 가리키는 사람이있는 경우 다음을 수행하십시오.

JSON.stringify( that.person, function( key, value) {
  if( key == 'parent') { return value.id;}
  else {return value;}
})

의 두 번째 매개 변수 stringify는 필터 함수 입니다. 여기서는 단순히 참조 된 객체를 ID로 변환하지만 순환 참조를 끊기 위해 원하는 모든 작업을 수행 할 수 있습니다.

다음을 사용하여 위 코드를 테스트 할 수 있습니다.

function Person( params) {
  this.id = params['id'];
  this.name = params['name']; 
  this.father = null;
  this.fingers = [];
  // etc.
}

var me = new Person({ id: 1, name: 'Luke'});
var him = new Person( { id:2, name: 'Darth Vader'});
me.father = him; 
JSON.stringify(me); // so far so good

him.father = me; // time travel assumed :-)
JSON.stringify(me); // "TypeError: Converting circular structure to JSON"
// But this should do the job:
JSON.stringify(me, function( key, value) {
  if(key == 'father') { 
    return value.id;
  } else {
    return value;
  };
});

BTW, parent여러 언어 (및 DOM)에서 예약어이므로 " "에 대해 다른 속성 이름을 선택합니다 . 이것은 길을 혼란스럽게 만드는 경향이 있습니다 ...


변수 parent를 무엇으로 변경해야 합니까?
— Esqarrouth

@Esqarrouth owner는 일반적으로 parent.
— DJDaveMark

10

것으로 보인다 도장이 형태로 JSON에 순환 참조를 나타낼 수 있습니다 :{"id":"1","me":{"$ref":"1"}}

다음은 그 예입니다.

http://jsfiddle.net/dumeG/

require(["dojox/json/ref"], function(){
    var me = {
        name:"Kris",
        father:{name:"Bill"},
        mother:{name:"Karen"}
    };
    me.father.wife = me.mother;
    var jsonMe = dojox.json.ref.toJson(me); // serialize me
    alert(jsonMe);
});​

생성 :

{
   "name":"Kris",
   "father":{
     "name":"Bill",
     "wife":{
          "name":"Karen"
      }
   },
   "mother":{
     "$ref":"#father.wife"
   }
}

참고 : dojox.json.ref.fromJson메서드를 사용하여 이러한 순환 참조 개체를 역 직렬화 할 수도 있습니다 .

기타 리소스 :

순환 참조가 있어도 DOM 노드를 JSON으로 직렬화하는 방법은 무엇입니까?

JSON.stringify는 순환 참조를 나타낼 수 없습니다.


안녕하세요, 답변 해 주셔서 감사합니다. 내 라이브러리로 jquery를 사용하고 있다고 말 했어야했습니다. 당시에는 관련성이 없다고 생각했습니다.
— user1012500

@ user1012500-Dojo는 jQuery와 함께 잘 작동합니다. 주로 기본 프레임 워크의 결함을 보완하기 위해 다른 라이브러리 또는 프레임 워크를 포함합니다. toJson및 fromJson메서드 를 추출하고 그 주위에 고유 한 jQuery 래퍼를 만들 수도 있습니다. 이렇게하면 전체 프레임 워크를 가져올 필요가 없습니다. 불행히도 jQuery에는이 기능이 기본적으로 제공되지 않으며 JSON.stringify는 이러한 유형의 객체를 처리 할 수 ​​없습니다. 따라서 위의 예 외에이 기능을 직접 코딩해야 할 수도 있습니다.
— Brandon Boone

1
안녕하세요 Brandon, 사이트에 다른 공간을 추가하기 때문에 문제를 해결하기 위해 다른 라이브러리를 추가하는 것을 주저합니다. 그러나 나는 dojo에게 기회를주고 당신의 모범을 내 것에 대해 사용하려고 시도했습니다. 그러나, 나는 (난 그냥 몇 가지를 시도했지만 주로 귀하의 예제를 기반으로 한, 그래서 나는 도장의 많은 지식이없는) 순환 참조 문제로 실행 : jsfiddle.net/Af3d6/1
— user1012500

1
JavaScript 객체 리터럴 과 혼동하지 않는 JSON 은 데이터 교환 형식 (예 : XML)이므로 함수를 포함 할 수 없습니다. 따라서 JSON 형식으로 직렬화하려면 호환되는 개체 리터럴이 필요합니다. 이 예제 는 준수하도록 예제를 수정합니다 (객체 인스턴스로 더 이상 작업하지 않기 때문에 원하는 것이 아닐 수도 있음). toJSON 함수를 제거하더라도 기본 프로토 타입 함수에 대한 참조는 여전히 유효하지 않게 만듭니다.
— Brandon Boone

1
Dojo의 ref 모듈은 바람처럼 내 모델을 문자열 화 / 파싱 할 수있었습니다. 내 시나리오에서 crockford의 cycle.js 라이브러리는 newtonsoft json.net을 사용하여 C # 객체를 직렬화하고 jsonpath를 사용하지 않기 때문에 성공하지 못했습니다 (cycle.js가 사용하는 것처럼). 좋은 오래된 도장이 내 하루를 구한 것 같습니다! 이 답변에 감사드립니다.
— JoaoPauloPaschoal

5

JSON에서 순환 참조를 처리하는 데 적합한 두 개의 모듈을 찾았습니다.

  1. 출력을 .parse ()에 대한 입력으로 사용할 수있는 CircularJSON https://github.com/WebReflection/circular-json . 브라우저 및 Node.js에서도 작동합니다. 또한 다음을 참조하십시오. http://webreflection.blogspot.com.au/2013/03/solving-cycles-recursions-and-circulars.html
  2. Isaacs json-stringify-safe https://github.com/isaacs/json-stringify-safe 이는 더 읽기 쉽지만 .parse에는 사용할 수 없으며 Node.js에서만 사용할 수 있습니다.

이들 중 하나가 귀하의 요구를 충족해야합니다.


4

특정 상황에서 원격 디버깅이 불가능했기 때문에 복잡한 개체를 페이지에 기록해야했기 때문에이 스레드에서 발생했습니다. Douglas Crockford (JSON의 인 셉터) 자체 cycle.js를 찾았습니다. 순환 참조는 구문 분석 후 다시 연결할 수 있도록 문자열로 주석을 달았습니다. de-cycled 딥 카피는 JSON.stringify를 통과해도 안전합니다. 즐겨!

https://github.com/douglascrockford/JSON-js

cycle.js :이 파일에는 JSON.decycle 및 JSON.retrocycle의 두 가지 함수가 포함되어있어 JSON으로 순환 구조 및 dag를 인코딩 한 다음 복구 할 수 있습니다. 이것은 ES5에서 제공하지 않는 기능입니다. JSONPath는 링크를 나타내는 데 사용됩니다.


3

노립

아래의 replacer 를 사용 하여 문자열 참조 (유사한 json-path )로 json 을 생성하여 참조 된 객체를 복제 / 순환합니다.

let s = JSON.stringify(obj, refReplacer());

그리고 이러한 "ref-json"에서 객체를 재생성하는 파서 기능


-13

순환 참조를 제거하기 위해 다음을 사용했습니다.

JS.dropClasses = function(o) {

    for (var p in o) {
        if (o[p] instanceof jQuery || o[p] instanceof HTMLElement) {
            o[p] = null;
        }    
        else if (typeof o[p] == 'object' )
            JS.dropClasses(o[p]);
    }
};

JSON.stringify(JS.dropClasses(e));

3
그러면 순환 참조가 아닌 jQuery및의 인스턴스가 제거 HTMLElement됩니까?
— ZachB

1
@ZachB 나는 그의 설정에서 이것들이 그에게 순환 적이라고 생각합니다 ... 그러나 문제는 자바 스크립트가 사용중인 언어이기 때문에 jquery 또는 심지어 HTML 요소가 있음을 의미하지 않는다는 것입니다.
— moeiscool
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.