2012-02-21 33 views
111

Tôi có một đối tượng (phân tích cây) có chứa các nút con được tham chiếu đến các nút khác.Serializing đối tượng có chứa giá trị đối tượng tuần hoàn

Tôi muốn tuần tự hóa đối tượng này, sử dụng JSON.stringify(), nhưng tôi nhận được: TypeError: cyclic object value vì các cấu trúc tôi đã đề cập.

Tôi làm cách nào để giải quyết vấn đề này? Nó không quan trọng với tôi cho dù các tài liệu tham khảo cho các nút khác được đại diện hay không trong đối tượng serialized.

Mặt khác, loại bỏ các thuộc tính này khỏi đối tượng khi chúng được tạo ra có vẻ tẻ nhạt và tôi sẽ không muốn thực hiện thay đổi cho trình phân tích cú pháp (narcissus).

+1

Chúng tôi không thể giúp bạn mà không có một số mã. Vui lòng đăng các bit có liên quan của đối tượng và/hoặc đầu ra JSON của bạn cùng với JS mà bạn sử dụng để nối tiếp nó. – Bojangles

+1

bạn có thể thêm một số tiền tố vào các thuộc tính được tham chiếu nội bộ không? – wheresrhys

+0

@Loic Sẽ rất có giá trị khi có câu trả lời là 'cycle.js' của Douglas Crockford ở đây, vì đây là giải pháp thích hợp nhất cho nhiều trường hợp. Có vẻ như thích hợp để bạn đăng câu trả lời đó, vì bạn là người đầu tiên tham khảo nó (trong bình luận của bạn bên dưới). Nếu bạn không muốn đăng nó như là một câu trả lời cho chính mình, cuối cùng tôi sẽ làm như vậy. –

Trả lời

157

Sử dụng tham số thứ hai của stringify, các replacer function, để loại trừ đối tượng đã serialized:

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/

Như một cách chính xác chỉ ra trong ý kiến ​​khác, mã này loại bỏ tất cả các "nhìn thấy" đối tượng, không chỉ "đệ quy".

Ví dụ, đối với:

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

kết quả sẽ không chính xác. Nếu cấu trúc của bạn như thế này, thì decycle của Crockford là một lựa chọn tốt hơn.

+2

aaah tốt đẹp! Cảm ơn, tôi sẽ thử điều này. Tôi tìm thấy một giải pháp được tạo ra bởi Douglas Crockford (https://github.com/douglascrockford/JSON-js/blob/master/cycle.js), nhưng vì tôi không chắc chắn về giấy phép đi kèm với nó, giải pháp dễ dàng mà bạn mô tả sẽ hoàn hảo! –

+3

@LoicDuros Giấy phép là "miền công cộng". Có nghĩa là, bạn có thể làm bất cứ điều gì bạn muốn với nó. –

+1

mã này tạo ra vòng lặp đi xe đạp, hãy cẩn thận khi sử dụng, rất có khả năng làm hỏng ứng dụng của bạn. cần các dấu chấm phẩy chính xác và không thể sử dụng được trên các đối tượng sự kiện! –

1

tiết kiệm nhiều và nó hiển thị đối tượng chu kỳ.

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

sản xuất

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

nhưng vẫn có vấn đề với mã này nếu ai đó tạo đối tượng với 'obj.b = this'' nếu ai đó biết làm thế nào để ngăn chặn các calcs rất dài được tạo ra từ một phạm vi sai với 'this' sẽ là tốt đẹp để xem ở đây –

+2

Điều này sẽ là' seen.indexOf (v)! = -1' –

2

tôi đã tạo ra một Gist GitHub có khả năng phát hiện các cấu trúc vòng và cũng de- và mã hóa chúng: https://gist.github.com/Hoff97/9842228

Để chuyển đổi chỉ cần sử dụng JSONE.stringify/JSONE.parse. Nó cũng mã hóa và mã hóa các chức năng. Nếu bạn muốn vô hiệu hóa điều này, chỉ cần xóa các dòng 32-48 và 61-85.

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

Bạn có thể tìm thấy một ví dụ fiddle đây:

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

+1

Đẹp, nhưng nó không xử lý Date .. – Seraph

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

Một điều kiện tiên quyết đã mất tích, nếu không các giá trị số nguyên trong đối tượng mảng được cắt ngắn, tức là [[2014/08/11 12: 30:13, 1095]] 1095 bị giảm xuống 095.

0

Tôi tạo quá một dự án github có thể tuần tự hóa đối tượng tuần hoàn và khôi phục lớp nếu bạn lưu nó trong hàng loạt tên thuộc tính như một String

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

Edit: tôi có chuyển đổi kịch bản của tôi cho NPM https://github.com/bormat/borto_circular_serialize và tôi phải thay đổi tên hàm từ tiếng Pháp sang tiếng Anh.

+0

Ví dụ này không phù hợp với Gist. Gist có lỗi. –

+0

Ý tưởng hay - nhưng một khi làm cho nó sẵn sàng :-) Nếu bạn làm cho nó được phân phối trong npm, có thể bạn sẽ phát triển ngay cả kiểu gõ cho điều đó, nó trở nên khá phổ biến. – peterh

+0

vâng, ý tưởng hay. – bormat

Các vấn đề liên quan