2012-05-01 17 views
48

Tôi đã có định nghĩa đối tượng JavaScript chứa tham chiếu vòng tròn: nó có thuộc tính tham chiếu đối tượng cha.Stringify (chuyển đổi thành JSON) một đối tượng JavaScript với tham chiếu vòng tròn

Nó cũng có các chức năng mà tôi không muốn chuyển qua máy chủ. Làm thế nào tôi sẽ serialize và deserialize các đối tượng này?

Tôi đã đọc rằng phương pháp tốt nhất để làm điều này là sử dụng chuỗi ký tự của Douglas Crockford. Tuy nhiên, tôi nhận được lỗi sau trong Chrome:

TypeError: Converting circular structure to JSON 

Mã:

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

Đây là một trường hợp thử nghiệm mà tôi đã tạo cho câu hỏi này. Có lỗi trong mã này nhưng về cơ bản tôi có đối tượng trong đối tượng và tham chiếu được truyền cho từng đối tượng để hiển thị đối tượng cha khi đối tượng được tạo. Mỗi đối tượng cũng chứa các hàm, mà tôi không muốn bị xâu chuỗi. Tôi chỉ muốn các thuộc tính như Person.Name.

Làm cách nào để tuần tự hóa trước khi gửi đến máy chủ và deserialize nó giả định rằng cùng một JSON được trả lại?

Trả lời

90

Thông tư cấu trúc lỗi xảy ra khi bạn có một tài sản của đối tượng đó là đối tượng chính nó trực tiếp (a -> a) hoặc gián tiếp (a -> b -> a) .

Để tránh thông báo lỗi, hãy thông báo cho JSON.stringify phải làm gì khi nó gặp tham chiếu vòng tròn. Ví dụ, nếu bạn có một người chỉ vào người khác ("cha mẹ"), có thể (hoặc không thể) trỏ đến người gốc, làm như sau:

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

Tham số thứ hai để stringify là một chức năng lọc. Ở đây nó chỉ đơn giản là chuyển đổi đối tượng được gọi thành ID của nó, nhưng bạn được tự do làm bất cứ điều gì bạn muốn phá vỡ tham chiếu vòng tròn.

Bạn có thể kiểm tra mã trên như sau:

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, tôi muốn chọn một tên thuộc tính khác nhau để "parent" vì nó là một từ dành riêng trong nhiều ngôn ngữ (và trong DOM). Điều này có xu hướng gây nhầm lẫn xuống đường ...

9

Dường như dojo thể đại diện tham chiếu vòng tròn trong JSON trong các hình thức: {"id":"1","me":{"$ref":"1"}}

Dưới đây là một ví dụ:

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

Tạo:

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

Lưu ý: Bạn cũng có thể hủy tuần tự hóa các đối tượng được tham chiếu vòng tròn này bằng cách sử dụng phương thức dojox.json.ref.fromJson.

Tài nguyên khác:

How to serialize DOM node to JSON even if there are circular references?

JSON.stringify can't represent circular references

+0

Xin chào, cảm ơn câu trả lời của bạn. Tôi nên nói rằng tôi đang sử dụng jquery như là thư viện của tôi. Tôi không nghĩ rằng nó có liên quan tại time.ill cập nhật bài viết của tôi. – user1012500

+0

@ user1012500 - Dojo hoạt động tốt cùng với jQuery. Tôi thường bao gồm các thư viện hoặc khung công tác khác để bù đắp cho những thiếu sót trong khung chính của tôi. Bạn thậm chí có thể trích xuất các phương thức 'toJson' và' fromJson' và tạo trình bao bọc jQuery của riêng bạn xung quanh chúng. Bằng cách đó bạn sẽ không cần phải kéo trong toàn bộ khuôn khổ. Thật không may, jQuery không có chức năng này ra khỏi hộp, và JSON.stringify không thể xử lý các kiểu đối tượng này. Vì vậy, ngoài các ví dụ trên, bạn có thể phải tự mình mã hóa chức năng này. –

+1

Xin chào Brandon, tôi do dự khi thêm một thư viện khác để giải quyết vấn đề vì nó thêm một dấu chân khác vào trang web. Tuy nhiên, tôi đã cho dojo một shot và cố gắng sử dụng ví dụ của bạn chống lại tôi. Tuy nhiên, tôi chạy vào vấn đề tham chiếu vòng tròn (tôi không có nhiều kiến ​​thức về võ đường, vì vậy tôi đã cố gắng một vài điều nhưng chủ yếu dựa trên ví dụ của bạn): http://jsfiddle.net/Af3d6/1/ – user1012500

4

Tôi đã tìm thấy hai mô-đun phù hợp để xử lý các tham chiếu vòng tròn trong JSON.

  1. CircularJSON https://github.com/WebReflection/circular-json có thể sử dụng đầu ra làm đầu vào .parse(). Nó cũng hoạt động trong trình duyệt & Node.js Xem thêm: http://webreflection.blogspot.com.au/2013/03/solving-cycles-recursions-and-circulars.html
  2. Isaacs json-stringify an toàn https://github.com/isaacs/json-stringify-safe mà có thể dễ đọc hơn, nhưng không thể được sử dụng cho .parse và chỉ có sẵn cho Node.js

Một trong hai cách này sẽ đáp ứng nhu cầu của bạn.

-9

tôi đã sử dụng sau đây để loại bỏ các tham chiếu vòng tròn:

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

Điều này sẽ loại bỏ các trường hợp 'jQuery' và' HTMLElement', chứ không phải tham chiếu vòng tròn? – ZachB

+0

@ ZachB tôi nghĩ rằng trong thiết lập của anh ta là hình tròn cho anh ta ... nhưng vấn đề là chỉ vì javascript là ngôn ngữ được sử dụng không có nghĩa là chúng ta có các yếu tố jquery hoặc thậm chí HTML. – moeiscool

0

xảy ra khi chủ đề này bởi vì tôi cần phải đăng nhập đối tượng phức tạp đến một trang, kể từ khi gỡ lỗi từ xa là không thể trong tình hình cụ thể của tôi. Tìm thấy Douglas Crockford (inceptor của JSON) sở hữu cycle.js, chú thích các tham chiếu vòng tròn dưới dạng các chuỗi sao cho chúng có thể được kết nối lại sau khi phân tích cú pháp. Bản sao sâu không biến đổi là an toàn để truyền qua JSON.stringify. Thưởng thức!

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

cycle.js: Tập tin này có chứa hai chức năng, JSON.decycle và JSON.retrocycle, mà làm cho nó có thể mã hóa cấu trúc chu kỳ và DAG trong JSON, và sau đó phục hồi lại được. Đây là khả năng màkhông cung cấp bởi ES5. JSONPath được sử dụng để đại diện cho các liên kết.