순환 참조를 사용하여 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와 함께 잘 작동합니다. 주로 기본 프레임 워크의 결함을 보완하기 위해 다른 라이브러리 또는 프레임 워크를 포함합니다. toJsonfromJson메서드 를 추출하고 그 주위에 고유 한 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.